I have a CSV file and we know excel does its thing with commas in a field by enclosing them in double quotation marks for instance i have a file
Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB
How can I use RegExp to replace the quotation marks with "." instead but only within quotation marks so i get
Product Name,Product Code
Product 1,AAA
Prod.A.B,BBB
as output
CSV handling functions (fgetcsv(), fputcsv()) are much better for this - they will handle edge cases and will likely be far more reliable than any regex you can come up with.
// Open the file
$fp = fopen($pathToCsvFile, 'r+');
// Create an array of modified data
$tmp = array();
while (($row = fgetcsv($fp, 8192)) !== FALSE) {
foreach ($row as &$field) $field = str_replace(',', '.', $field);
$tmp[] = $row;
}
// Truncate the file and put the pointer at the beginning
ftruncate($fp, 0);
rewind($fp);
// Write the modified data back and close the file
foreach ($tmp as $row) {
fputcsv($fp, $row);
}
fclose($fp);
EDIT Following your comment about not wanting to read from/write to disk, you can do this:
// Lets say the raw CSV data is held in this variable as a string
$rawCsvData = 'Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB';
// Open a virtual file pointer to memory and fill it with your data
$fp = fopen('php://memory', 'w+');
fwrite($fp, $rawCsvData);
// Start from the beginning of the pointer
rewind($fp);
// ... INSERT CODE FROM ABOVE HERE (minus the fopen()/fclose())
$modifiedCsvData = stream_get_contents($fp);
fclose($fp);
This will do multiple replaces, and remove the quotes.
<?php
$data = 'Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB';
$rgx = '/"(.+?)"/';
preg_match_all($rgx, $data, $matches);
$x = 0; $max = count($matches[0]);
while($x < $max){
$replace = str_replace(",", ".", $matches[1][$x]);
$data = str_replace($matches[0][$x], $replace, $data);
$x++;
}
echo $data;
?>
Related
i am having difficulties with extracting specific text from a text file. I have tried many different ways like using fopen or file to open the file but this wont allow me to use any of the string functions. So i have decided to use file_get_contents and extract the text i want with the string methods as follows:
<?php
$data = [];
$file =
file_get_contents("data.txt", 0, NULL, 148);
list($id, $data_names) = preg_split('[:]', $file);
array_push($names, $data_names);
echo $emails[0];
?>
I used preg_split to split the text i want at a specific character (:) and i put the data in an array. Which worked for the first line but i don't know how to go about doing it for the rest of the lines, i've tried a while loop but that just ends up in an infinite loop.
data.txt formatted like this:
1:hannah.Smith
2:Bob.jones
3:harry.white
....
Any suggestions on how to do this or a better approach would be greatly appreciated.
There is a function for that. This isn't CSV but change the delimiter. To just get the names:
$handle = fopen("data.txt", "r"));
while(($line = fgetcsv($handle, 0, ":")) !== FALSE) {
$names[] = $line[1];
}
To index the names by the ids:
while(($line = fgetcsv($handle, 0, ":")) !== FALSE) {
$names[$line[0]] = $line[1];
}
To get the ids and names in a multidimensional array, use:
while(($names[] = fgetcsv($handle, 0, ":")) !== FALSE) {}
Well you are not assigning the return value of file_get_contents to a variable. So the contents of the file are not being used.
You can use the file function. It reads the contents of a file to an array. Each element of the array is a line in the file. You can then loop over the array and parse each line. For example:
$names = array();
$file = file_get_contents("data.txt");
for ($count = 0; $count < count($file); $count++) {
list($id, $name) = $file[$count];
$names[] = $name;
}
/** print the contents of the names array */
print_R($names);
My ideal fix would be a function that can take a CSV file that does not have forced encapsulation (no quotes around values if the value has no spaces or is just a number) and convert it into a CSV file that makes sure every field is encapsulated with double quotes.
<?php
$raw_file = BASE_DIR."pathto/csv.csv";
$fixed_file = BASE_DIR."pathto/fixed.csv";
convert_file($raw_file, $fixed_file);
//move on with life!!
?>
Thanks for you help!
Use fgetcsv to get the contents of your original csv file and fputcsv (using the fourth parameter) to build the encapsulated file.
For example, supposing your column separator is ; :
<?php
$raw_file = BASE_DIR."pathto/csv.csv";
$fixed_file = BASE_DIR."pathto/fixed.csv";
// Getting contents
$raw_handle = fopen($raw_file, 'r');
$contents = array();
while (($data = fgetcsv($raw_handle, 0, ';')) !== false) {
$contents[] = $data;
}
fclose($raw_handle);
// Putting contents
$fixed_handle = fopen($fixed_file, 'w');
foreach ($contents as $line) {
fputcsv($fixed_handle, $line, ';', '"');
}
fclose($fixed_handle);
//move on with life!!
?>
I have csv data in PHP such as the following (note, it's text with new line characters in it, not a file):
$data = 'A,B,C,D,E,F,G,H
1,1,2014-12-10,5,1,2,0,2
2,7,2014-12-09,9,0,,7,2';
How can I extract a column as an array that excludes the headers? For example, if I wanted to extract the 4th column, it would include 5 and 9.
UPDATE: I have tried
$te = array_column($data,'D');
and I get the error: Warning: array_column() expects parameter 1 to be array,
You can use str_getcsv() to read each row as an array (discarding the first to skip headers). Then just keep the relevant column, e.g.:
$lines = preg_split("/(?:\r?\n|\r\n?)/", $data); // Split lines
array_shift($lines); // Discard header
$result = array();
foreach ($lines as $csv) {
$row = str_getcsv($csv);
$result[] = $row[3];
}
var_dump($result);
As per cHao suggestion in the comment below, if you need a more robust support of generic CSV data, you can dump the string to a virtual file and use fgetcsv() instead (which already handles parsing of multiple lines of input correctly):
$fp = fopen('php://temp', 'r+');
fputs($fp, $data);
fseek($fp, 0);
$result = array();
fgetcsv($fp);
while (false != ($row = fgetcsv($fp))) {
$result[] = $row[3];
}
fclose($fp);
var_dump($result);
If this a comma delimited string, you could use str_getcsv() in this case:
// load the string and explode, then apply str_getcsv
$data = array_map('str_getcsv', explode("\n", $request->getResponseBody()));
array_shift($data); // remove the header
$fourth_column = array();
foreach($data as $line) {
if(!empty($line[3])) {
$fourth_column[] = $line[3]; // indices start at zero
}
}
I have a php code that will read and parse csv files into a multiline array, what i need to do next is to take this array and let simplehtmldom fire off a crawler to return some company stocks info.
The php code for the CSV parser is
$arrCSV = array();
// Opening up the CSV file
if (($handle = fopen("NASDAQ.csv", "r")) !==FALSE) {
// Set the parent array key to 0
$key = 0;
// While there is data available loop through unlimited times (0) using separator (,)
while (($data = fgetcsv($handle, 0, ",")) !==FALSE) {
// Count the total keys in each row $data is the variable for each line of the array
$c = count($data);
//Populate the array
for ($x=0;$x<$c;$x++) {
$arrCSV[$key][$x] = $data[$x];
}
$key++;
} // end while
// Close the CSV file
fclose($handle);
} // end if
echo "<pre>";
echo print_r($arrCSV);
echo "</pre>";
This works great and parses the array line by line, $data being the variable for each line. What i need to do now is to get this to be read via simplehtmldom, which is where it breaks down, im looking at using this code or something very similar, im pretty inexperienced at this but guess i would be needing a foreach statement somewhere along the line.
This is the simplehtmldom code
$html = file_get_html($data);
$html->find('div[class="detailsDataContainerLt"]');
$tickerdetails = ("$es[0]");
$FileHandle2 = fopen($data, 'w') or die("can't open file");
fwrite($FileHandle2, $tickerdetails);
fclose($FileHandle2);
fclose($handle);
So my qyestion is how can i get them both working together, i jave checked out simplehtmldom manual page several times and find it a littlebit vague in this area, the simplehtmldom code above is what i use in another function but by direclty linking so i know that it works.
regards
Martin
Your loop could be reduced to (yes, it's the same):
while ($data = fgetcsv($handle, 0, ',')) {
$arrCSV[] = $data;
}
Using SimpleXML instead of SimpleDom (Since it's standard PHP):
foreach ($arrCSV as $row) {
$xml = simplexml_load_file($row[0]); // Change 0 to the index of the url
$result = $xml->xpath('//div[contains(concat(" ", #class, " "), " detailsDataContainerLt")]');
if ($result->length > 0) {
$file = fopen($row[1], '2'); // Change 1 to the filename you want to write to
if ($file) {
fwrite($file, (string) $result->item(0));
fclose($file);
}
}
}
that should do it if I understood correctly...
whats wrong with this, when i echo out a row from the csv file and concat anything to the end of the row, it doesnt show up, instead all the rows are echo'ed and the concated string only shows up once at the very end, is this some kind of buffering thing that wont let me concat strings with stuff from my csv file, its running on my local wamp server, and i have tryed different line delimiter in my expload function, im sure the file only uses \n at the end of a line
im trying to parse a csv file row by row so i can check the content of it before i use it to construct an sql statement and insert it into my database.
$file = fopen($filename, "r")
$filesize = filesize($filename);
$filecontent = fread($file, $filesize);
fclose($file);
$rows = explode("\n", trim($filecontent));
foreach ($rows as $row)
{
echo $row . '<br />';
}
You are splitting the string by the string \n. Unless the actual string "\n" appears anywhere in the file, this will probably do nothing. You probably meant "\n" (double quotes), which makes this an actual line break.
Your overall process is terribly inefficient though. You should use fgetcsv and process the file line by line, instead of reading it into memory all at once.
$handle = fopen('test.csv', 'r');
while (($row = fgetcsv($handle)) !== false) {
foreach ($row as $field) {
echo $field . '<br />';
}
}
fclose($handle);
Use fgetcsv() function to convert a CSV file to an array:
$csvFile = "test.csv";
$csvSeparator = ",";
$csvFileLength = filesize($csvFile);
$handle = fopen($csvFile, "r");
$csvData = fgetcsv($handle, $csvFileLength, $csvSeparator);
fclose($handle);
Dump the data to show the structure:
var_dump($csvData);
Now you can convert the data to use in database.