将float的正确值写入csv文件

In the csv file, I have lines with this structure :

Name;timestamp;floatValue
Name;timestamp;floatValue
Name;timestamp;floatValue
...

In my code, I check each value in the line, I filter them,then I want to correct the float value by calling the function floatval, because I have wrong values sometimes like : .904 or 2,454 and using this function returns the right formatted one.

    <?php

    if (($handle = fopen('file.csv', "r+")) !== false) {
        while (($line = fgetcsv($handle, 1024, ";")) !== false) {

          $headers = [
              'name',
              'timestamp',
              'floatValue',
          ];
          $line = array_combine($headers, $line);
          $args = array('name' => array('filter' => FILTER_VALIDATE_REGEXP,
                                                      'options' => array('regexp' => '/^[a-zA-Z0-9_:.()\/]*$/'), ),
                        'timestamp' => array('filter' => FILTER_CALLBACK,
                                                            'options' => 'validateDate', ),
                         'floatValue' => array('filter' => FILTER_VALIDATE_FLOAT),);
    $result = filter_var_array($line, $args);
    $line = correctFloat($line);
    print_r($line);
    }

    }

    fclose($handle);

    function validateDate($date)
    {
      if (!preg_match("/^\d{8}$/", substr($date, 0, 8))) {
          return false;
      }
      if (!checkdate(substr($date, 4, 2), substr($date, 6, 2), substr($date, 0, 4))) {
          return false;
      }
      if (substr($date, 8, 2) > 23 || substr($date, 10, 2) > 59 || substr($date, 12, 2) > 59) {
          return false;
      }

      return true;
    }


function correctFloat($line){
  $float = $line['floatValue'];
  $value = str_replace(",",".",$float);
  return str_replace($float,floatval($value),$line);
}


    ?>

Now I'm stuck how to write the correct value inside the file in the right line?

I tried this:

fwrite($handle,implode(";",correctFloat($line)));

But it didn't work. How to re-write each line into the file in the right position with the correct float without losing data? Any idea?

:::EDIT:::

I also tried to use a temporary file:

$temp = tmpfile();
fputcsv($temp,correctFloat($line),';');
fwrite($handle,fread($temp, 1024));

but I didn't get a good result. nothing happened inside the file.

Example

Input :

Name;timestamp;.23
Name;timestamp;2,4578
Name;timestamp;1.23

Expected output:

Name;timestamp;0.23
Name;timestamp;2.4578
Name;timestamp;1.23

In this example: 2,4578 should be in the output : 2.4578 (I replace the comma with '.' using the function correctFloat($line) above )

New try:

$newline = correctFloat(array_combine($headers, $line));
array_push($newline,chr(10));
$l = implode(";",$newline);
fwrite($handle,$l);
rewind($handle);

Only the first value changes and then the file is refreshing without getting out of the loop.

Requirements: Given a CSV input file then create an output file that has the float fields formatted correctly.

How:

  • Read the input file one record at a time splitting it into fields
  • Format the floating point string into a valid string ny replacing comma with decimal point.
  • Apply some validation to the fields
  • format the fields as a valid output string (correctFloat)
  • append to the output file.

Note: I have used test data so the validation is not checked. This code just formats the output from the input.

Source code I used

Code:

Input / Output file names:

define('DATA_FILE', 'Q42208643.dat');
define('DATA_FILE_OUT', 'Q42208643.out.dat');

Headers and Validation:

// setup field names and validiation rules
$headers = ['name',  'timestamp', 'floatValue',];

$args = array(
              'sensor_internal_id' => array('filter' => FILTER_VALIDATE_REGEXP,
                                                      'options' => array('regexp' => '/^[a-zA-Z0-9_:.()\/]*$/'), ),

              'timestamp' => array('filter' => FILTER_CALLBACK,
                                   'options' => 'validateDate', ),

               'value' => array('filter' => FILTER_VALIDATE_FLOAT),
        );

Process input and output files:

if (($handle = fopen(DATA_FILE, "r+")) !== false) {

    $fOut = fopen(DATA_FILE_OUT, "wb");

    while (($fields = fgetcsv($handle, 1024, ";")) !== false) {

        $fields[2] = str_replace(",", ".", $fields[2]); // ensure float sting is valid

        $namedFields = array_combine($headers, $fields);
        $result = filter_var_array($namedFields, $args);

        $outLine = correctFloat($fields);
        fwrite($fOut, $outLine . PHP_EOL);
    }
    fclose($handle);
    fclose($fOut);
}

functions:

function validateDate($date)
{
  if (!preg_match("/^\d{8}$/", substr($date, 0, 8))) {
      return false;
  }
  if (!checkdate(substr($date, 4, 2), substr($date, 6, 2), substr($date, 0, 4))) {
      return false;
  }
  if (substr($date, 8, 2) > 23 || substr($date, 10, 2) > 59 || substr($date, 12, 2) > 59) {
      return false;
  }

  return true;
}


function correctFloat($fields) {
  $fields[2] = floatval($fields[2]);
  return implode(';', $fields);
}

Sample input:

122222;1487075470;.123
233333;1487075470;2,345
344444;1487075470;3.678

Sample Output:

122222;1487075470;0.123
233333;1487075470;2.345
344444;1487075470;3.678

Try this rewind() Example code :

$handle = fopen('output.txt', 'r+');

fwrite($handle, 'Really long sentence.');
rewind($handle);
fwrite($handle, 'Foo');
rewind($handle);

echo fread($handle, filesize('output.txt'));

fclose($handle);

// Output: Foolly long sentence.

Here rewind function will take you at the start of current line then you just need to replace all characters in that line [Note : if your current data is less then old data then you'll see old values appended at the end so just replace all remaining characters with '' (blank)

Let me know if it helped otherwise I'll provide the way to use it in your code