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:
fields
correctFloat
)Note: I have used test data so the validation is not checked. This code just formats the output from the input.
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