I need to read the data from a file that can be either comma or tab delimited. I now that there is a function getcsv but it accepts only one possible delimiter.
Any ideas how to handle this?
Thanks.
Starting from PHP 5.3, you can use str_getcsv() to read individual lines using different delimiters.
$someCondition = someConditionToDetermineTabOrComma();
$delimiter = $someCondition ? "," : "\t";
$fp = fopen('mydata.csv', 'r');
while ( !feof($fp) )
{
$line = fgets($fp, 2048);
$data = str_getcsv($line, $delimiter);
doSomethingWithData($data);
}
fclose($fp);
You can specify a delimiter for fgetcsv(). This is an example of reading tab-delimited files,
while (($data = fgetcsv($handle, 1000, "\t")) !== FALSE) {
...
}
Here is an example that will read mydata.txt CSV fields
$tab = "\t";
$fp = fopen('mydata.txt', 'r');
while ( !feof($fp) )
{
$line = fgets($fp, 2048);
$data_txt = str_getcsv($line, $tab);
//Get First Line of Data over here
print_r($data_txt);
exit;
}
fclose($fp);
$filePath = "somefile.txt";
$delimiter = "\t";
$file = new \SplFileObject($filePath);
while (!$file->eof()) {
$line = $file->fgetcsv($delimiter);
print_r($line);
}
Read the whole file, or line by line and split it using split.
There you can include a regex with arbitrary delimiters. I have not PHP here to test a statement, but php.net -> search for split().
There you also have a comment relating to regex.
you can try explode
explode ( string $delimiter , string $string [, int $limit ] );
Here is the function that I added to my utilities library for future use. I derived it from NSSec's answer.
This solution allows you to specify whether you want to use the first line as keys for the array. I will probably add the ability to pass an array to be used for keys for the $first_line_keys parameter at some point.
/**
* Converts a CSV file into an array
* NOTE: file does NOT have to have .csv extension
*
* $file - path to file to convert (string)
* $delimiter - field delimiter (string)
* $first_line_keys - use first line as array keys (bool)
* $line_lenght - set length to retrieve for each line (int)
*/
public static function CSVToArray($file, $delimiter = ',', $first_line_keys = true, $line_length = 2048){
// file doesn't exist
if( !file_exists($file) ){
return false;
}
// open file
$fp = fopen($file, 'r');
// add each line to array
$csv_array = array();
while( !feof($fp) ){
// get current line
$line = fgets($fp, $line_length);
// line to array
$data = str_getcsv($line, $delimiter);
// keys/data count mismatch
if( isset($keys) && count($keys) != count($data) ){
// skip to next line
continue;
// first line, first line should be keys
}else if( $first_line_keys && !isset($keys) ){
// use line data for keys
$keys = $data;
// first line used as keys
}else if($first_line_keys){
// add as associative array
$csv_array[] = array_combine($keys, $data);
// first line NOT used for keys
}else{
// add as numeric array
$csv_array[] = $data;
}
}
// close file
fclose($fp);
// nothing found
if(!$csv_array){
return array();
}
// return csv array
return $csv_array;
} // CSVToArray()
Related
I have one excel orginal.csv file
ID Name Price
1 Xblue 12
2 Yblue 32
3 Zblue 52
And another copy.csv file
ID Name Price
1 Xblue 89
2 Yblue 43
3 Zblue 45
I want to replace rows from orginal.csv to copy.csv where ID is the same.
Can I do this manually or maybe somehow using PHP?
I search for some options on the internet, but I only found getcsv and readcsv functions that can't help me in this case. Cause this is something like updating CSV file.
It may end up in request timeout in PHP because it requires so many loops to do it. If someone can reduce the time complexity of this program then it will work. if it even works it will take a lot of time to do it.
while(! feof($f_pointer)){ //open old csv to update loop1
$ar=fgetcsv($f_pointer); // getting first row
for($i=0;$i<count($ar);$i++){ //loop2 first row array
$f_pointer2=fopen("new.csv","r"); open new csv to get data
while(! feof($f_pointer2)){ // loop3 to find ID in new csv
$ar2=fgetcsv($f_pointer2); //getting each row in array
for($j=0;$j<count($ar2);$j++){ //loop4 to compare id of old csv to new csv and update data
if($ar[i] == $ar2[j]){
foreach ($ar2 as $fields) { //loop5
fputcsv($f_pointer, $fields);
}
}
}
}
}
}
?>
I've created a little soulution. If order is important you don't have to index the array and loop through the copied array.
<?php
if(file_exists('output.csv'))
{
unlink('output.csv');
}
function fputcsv_eol($handle, $array, $delimiter = ',', $enclosure = '"', $eol = "\n") {
$return = fputcsv($handle, $array, $delimiter, $enclosure);
if($return !== FALSE && "\n" != $eol && 0 === fseek($handle, -1, SEEK_CUR)) {
fwrite($handle, $eol);
}
return $return;
}
function scanFile($sFilename, $iIndexColumn)
{
$rFile = fopen($sFilename, 'r');
$aData = array();
while(($aLine = fgetcsv($rFile)) !== false)
{
$aData[$aLine[$iIndexColumn]] = $aLine;
}
fclose($rFile);
return $aData;
}
$iIndexColumn = 0;
$iValueColum = 2;
$aOriginalData = scanFile('original.csv', 0);
$aCopyData = scanFile('copy.csv', 0);
foreach($aOriginalData as $iID => $aOriginalDatum)
{
if(array_key_exists($iID, $aCopyData))
{
$aCopyData[$iID] = $aOriginalDatum;
}
}
$rFile = fopen('output.csv', 'w');
foreach($aCopyData as $aCopyDatum)
{
fputcsv_eol($rFile, $aCopyDatum, ',', '"',"\r\n");
}
fclose($rFile);
I want to do if conditional between text data and variable data then delete the line
Example
I have a txt data with usernames like ( one two one three one) every user in line,
And i want to delete all data except "one" username
My Code;
if(file_get_contents('visitors.txt') != "one") {
$GetLine = ;
function removeLine ($url, $lineToRemove)
{
$data = file_get_contents($url);
$lines = explode(PHP_EOL, $data);
$lineNo = 1;
foreach($lines as $line)
{
$linesArray[$lineNo] = $line;
$lineNo++;
}
unset($linesArray[$lineToRemove]);
return implode("\n", $linesArray);
}
$data = removeLine ("username.txt", $getLine);
echo $data
}
the function is used to remove lines.
My problem is doing if with the data + $getLine number, I just want to remove all the lines except line that has one word.
Can simply do it with a regular expression:
$file = preg_grep('#one#', file('file.txt'));
This will make $file an array holding only lines containing the string "one". To turn the array back into a string, you just implode it.
If you only want to echo the lines containing "one", you can also use iterators:
$file = new RegexIterator(new SplFileObject("file.txt"), '#one#');
foreach ($file as $content) {
echo $content, PHP_EOL;
}
This will go over the file line by line and echo any line having the string one in it. The benefit is that it doesn't use two arrays as intermediate structures.
Just a note, you shouldn't be defining functions inside an if statement.
Also, unless I'm misunderstanding, you shouldn't even need line numbers.
function remove_line( $data, $remove ){
$lines = explode( PHP_EOL, $data ); // Convert to Array
$new_lines = ''; // Start a new variable we'll add to in a loop
foreach( $lines as $line ){
$line = trim( $line ); // Trim Whitespace
if( $line != $remove ){
// Line isn't a line we want removed, so save it plus an EOL
$new_lines .= $line.PHP_EOL;
}
}
return $new_lines;
}
Now if you load in a file like so: $file = file_get_contents( 'my-file.txt' ); that contains the following:
One
Two
One
Three
One
Once you run it through the remove_line function, you'll end up something like:
$file = file_get_contents( 'my-file.txt' );
$new_file = remove_line( $file, 'One' );
var_dump( $new_file ); // Returns: string(10) "Two Three "
I have a txt file which has a lot of lines and the values in every line are separated with commas.
I want to read the 1st line alone which I did already using fgets :
$head = fgets(fopen($file, 'r'));
$headValues = explode(',', $head);
but now I want to read every other line from line 2 until the end of file and put those values into an array.
I searched for similar solutions but couldn't find any
Just use descriptor
$fd = fopen($file, 'r');
$head = fgets($fd);
$headValues = explode(',', $head);
$data = [];
while(($str = fgets($fd)) !== false) {
$otherValues = explode(',', $str);
$data[] = $otherValues;
}
This uses fgetcsv for the lines you care about and uses array_combine to put the headers and the line data together.
$fh = fopen($file, 'r');
$headValues = fgetcsv($fh);
$data = [];
while (true) {
if ( ($values = fgetcsv($fh)) === false ) {
break;
}
$data[] = array_combine($headValues, $values);
if ( fgets($fh) === false ) {
break;
}
}
fclose($fh);
print_r($data);
It checks at each read in case the EOF has been reached and then breaks out of the read loop.
You could use file(), array_map() and array_shift() :
$lines = file($file) ; // get file as array.
$lines = array_map(function($l){ return explode(',', $l); }, $lines);
$headValues = array_shift($lines); // get first values (removed from $lines)
So, $lines will contains all lines except the first one.
I have a .CSV file with static column names. I receive it daily so i have to automatically edit it on a daily base.
On the first line are the row names for example: row1;row2;row3,row4,row5
for example when i want to unset "row2" and "row4".
How can i unset multiple rows based on a name?
I found a some tutorials about deleting lines or rows based on a row position but nothing that helps me completely.
This is what is have now:
$inFile = 'original.csv';
$outFile = 'edited.csv';
$delimiter = ';';
$enclosure = '"';
$read = fopen($inFile, 'r');
$write = fopen($outFile, 'w');
if ($write && $read) {
while (($data = fgetcsv($read)) !== FALSE) {
// how to unset multiple row names
fputcsv($write, $data, $delimiter, $enclosure);
}
}
fclose($write);
fclose($read);
Also, do i need to use the delimiter and enclosure when i fopen the original file?
Hi you can try the updated following code:
$inFile = 'original.csv';
$outFile = 'edited.csv';
$delimiter = ';';
$enclosure = '"';
$removeFields = array('color');
$write = fopen($outFile, 'w');
if ($write) {
$rows = file($inFile);
$first = false;
foreach($rows as $row) {
$csvToPHP = str_getcsv($row, $delimiter, $enclosure);
if (!$first) {
$headers = array_flip($csvToPHP);
$first = true;
}
foreach($removeFields as $remove) {
unset($csvToPHP[$headers[$remove]]);
}
fputcsv($write, $csvToPHP, $delimiter, $enclosure);
}
}
fclose($write);
I used a test csv original.csv:
name,age,color
test1,20,red
test2,32,blue
test3,92,green
test4,12,red
test5,56,orange
Result edited.csv:
name
test1
test2
test3
test4
test5
Hope it helps. Good luck!
It seems that the delimiter of csv file edited and saved by OpenOffice Excel is ";" while microsoft office excel is ",", how should i write a program to parse the csv file no matter which delimiter it uses?
I'm using this function in one of my apps to determine which separator is used:
function get_separator( $csvstring, $fallback = ';') {
$seps = array(';',',','|',"\t");
$max = 0;
$separator = false;
foreach($seps as $sep){
$count = substr_count($csvstring, $sep);
if($count > $max){
$separator = $sep;
$max = $count;
}
}
if($separator) return $separator;
return $fallback;
}
It basically checks which separator occurs at most and returns it. It works without problems for about two years now
Use SplFileObject::getCsvControl method.
Example usage:
<?php
$csvFileObject = new SplFileObject($_FILES["csv"]["tmp_name"]);
list($delimiter, $enclosure) = $csvFileObject->getCsvControl();
$lines = fopen($_FILES["csv"]["tmp_name"], 'r');
if($lines) {
while (($line = fgetcsv($lines, 4096, $delimiter, $enclosure)) !== false) {
//do something
}
}
Reference: http://php.net/manual/en/splfileobject.getcsvcontrol.php
fgetcsv() allows you to specify the delimiter as the third argument.
As for automatically detecting, there are some interesting answers for this question.