Use PHP to convert text file into array - php

I have a text file here which I need to be able to convert into rows to extract the second, third, fourth, and fifth values from.
The first 7 values of each row are tab delimited, then there is a newline, then the final three values are tab delimited.
I removed the interrupting newlines so that each row is fully tab delimited.
<?php
$file="140724.txt";
$fopen = fopen($file, "r");
$fread = fread($fopen,filesize("$file"));
fclose($fopen);
$remove = "\n";
split = explode($remove, $fread);
foreach ($split as $string)
{
echo "$string<br><br>";
}
?>
Which produces this.
I'm not sure where to progress from this point. I'm teaching myself PHP and am still quite new to it, so I don't even know if where I've started from is a good place. My instinct is to write the previous output to a new textfile, then create another block of code similar to the first but exploding based on tabs, this time.
Help?

You can process this file in one go like this:
<?php
$file="140724.txt";
$fopen = fopen($file, 'r');
$fread = fread($fopen,filesize($file));
fclose($fopen);
$remove = "\n";
$split = explode($remove, $fread);
$array[] = null;
$tab = "\t";
foreach ($split as $string)
{
$row = explode($tab, $string);
array_push($array,$row);
}
echo "<pre>";
print_r($array);
echo "</pre>";
?>
The result will be a jagged array:
You will need to clean up the 1st and the last element.

That is structured data, delimited by tabs. You can use fgetcsv() to read that data into an array. For an example see the PHP documentation.

<?php
$myfile = fopen("test.txt", "r") or die("Unable to open file!");
// Output one line until end-of-file
while(!feof($myfile)) {
$text[] = fgets($myfile);
}
fclose($myfile);
print_r($text);
?>

There is another answer here which converts file/raw strings into an associative array. It is really very handy in such cases.
function tab_to_array($src='', $delimiter=',', $is_file = true)
{
if($is_file && (!file_exists($src) || !is_readable($src)))
return FALSE;
$header = NULL;
$data = array();
if($is_file){
if (($handle = fopen($src, 'r')) !== FALSE)
{
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
}
else{
$strArr = explode("\n",$src);
foreach($strArr as $dataRow){
if($row = explode($delimiter,$dataRow))
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
}
}
return $data;
}
/**
* Example for file
*/
print_r(tab_to_array('example.csv'));
/**
* Example for raw string
*/
$str = "name number
Lorem 11
ipsum 22";
print_r(tab_to_array($str, "\t", false));

Related

how to replace one line of a file with php

I want to replace one line of a file with php, how can i do it?
This is the code where i print the line that I want to replace:
$file = fopen("file.dat", "a+");
$eqs = file_get_contents("file.dat");
$eqs = preg_split( "/\n/", $eqs );
foreach ($eqs as $valor) {
if(strpos($valor, $sn) !== false){
echo $valor; //this is the line to replace
} else{
echo "Not found";
}
}
Thanks in advance
As deceze♦ mentioned, unless the line is of fixed length, the easiest way is to process the whole file and output it to a new file.
Create a variable $newdata to append the processed data.
If your strpos statement !== false then you can change that text with the $replace_text variable and append that instead.
Once the loop has finished save your output to a new file. (If PHP has the appropriate permissions)
$file = fopen("file.dat", "a+");
$eqs = file_get_contents("file.dat");
$eqs = preg_split( "/\n/", $eqs );
$newdata = "";
foreach ($eqs as $valor) {
if(strpos($valor, $sn) !== false){
echo $valor; //this is the line to replace
$replace_text = "test";
$newdata = $newdata.$replace_text."/\n/";
} else{
$newdata = $newdata.$valor."/\n/";
}
}
$myfile = fopen("newfile.dat", "w") or die("Unable to open file!");
fwrite($myfile, $newdata);
fclose($myfile);
I would suggest this solution because it saves resources by processing line by line.
$source = fopen('file.dat', "r");
$target = fopen('file.dat.tmp', "w");
while ($line = fgets($source)) {
if(strpos($line, $sn) === false){
fputs($target, $line);
}
}
fclose($source);
fclose($target);
unlink('file.dat');
rename('file.dat.tmp','file.dat');

explode text file into array depend on comma

I'd like to convert my text.tx into array depend on only comma for example:
if I have this text:
so what I need to execute my array like that:
please check my code, my code not work well because it's depend on comma and newline:
<?php
$lines = file ("text.txt");
foreach($lines as $line) {
$data[] = explode(',', $line);
}
?>
<pre>
<?php
print_r($data);
?>
</pre>
$handle = fopen("text.txt", "r");
if ($handle) {
$data = [];
while (($line = fgets($handle)) !== false) {
$data[] = explode(',', $line);
}
fclose($handle);
echo "<pre>";
print_r($data);
} else {
// error opening the file.
}

skip columns while converting tab delimited text file to csv php

I am trying to convert a tab delimited file to csv. The problem is its a huge file. 100000 plus records. And i want only specific columns from that file. The file is not generated by me but by amazon so i cant really control the format.
The code i made works fine. But i need to ignore/remove some columns or rather i want only few columns from that. How do i do that without effecting the performance of conversion from txt to csv.
$file = fopen($file_name.'.txt','w+');
fwrite($file,$report);
fclose($file);
$handle = fopen($file_name.".txt", "r");
$lines = [];
$row_count=0;
$array_count = 0;
$uid = array($user_id);
if (($handle = fopen($file_name.".txt", "r")) !== FALSE)
{
while (($data = fgetcsv($handle, 100000, "\t")) !== FALSE)
{
if($row_count>0)
{
$lines[] = str_replace(",","<c>",$data);
array_push($lines[$array_count],$user_id);
$array_count++;
}
$row_count++;
}
fclose($handle);
}
$fp = fopen($file_name.'.csv', 'w');
foreach ($lines as $line)
{
fputcsv($fp, $line);
}
fclose($fp);
I am using unset to remove any column. But is there a better way ? for multiple columns.
I would do that by checking keys. For example:
// columns keys you don't wanna skip
$keys = array(0, 1, 3, 4, 7, 9);
$lines = file($file_name);
$result_lines = array();
foreach ($lines as $line) {
$tmp = array();
$tabs = explode("\t", $line);
foreach($tabs as $key => $value){
if(in_array($key, $keys)){
$tmp[] = $value;
}
}
$result_lines[] = implode(",", $tmp);
}
$finalString = implode("\n", $result_lines);
// Then write string to file
Hope it helps.
Cheers,
Siniša
In its simplest form i.e. without worrying about removing columns from the output this will do a simple read line and write line, therefore no need to maintain any memory hungry arrays.
$file_name = 'tst';
if ( ($f_in = fopen($file_name.".txt", "r")) === FALSE) {
echo 'Cannot find inpout file';
exit;
}
if ( ($f_out = fopen($file_name.'.csv', 'w')) === FALSE ) {
echo 'Cannot open output file';
exit;
}
while ($data = fgetcsv($f_in, 8000, "\t")) {
fputcsv($f_out, $data, ',', '"');
}
fclose($f_in);
fclose($f_out);
This is one way of removing the unwanted columns
$file_name = 'tst';
if ( ($f_in = fopen("tst.txt", "r")) === FALSE) {
echo 'Cannot find inpout file';
exit;
}
if ( ($f_out = fopen($file_name.'.csv', 'w')) === FALSE ) {
echo 'Cannot open output file';
exit;
}
$unwanted = [26,27]; //index of unwanted columns
while ($data = fgetcsv($f_in, 8000, "\t")) {
// remove unwanted columns
foreach($unwanted as $i) {
unset($data[$i]);
}
fputcsv($f_out, $data, ',', '"');
}
fclose($f_in);
fclose($f_out);

from csv to array with end of line chars

To parse CSV files in php im using this function:
private function _csvToArray($url, $delimiter=',')
{
$csvData = file_get_contents($url);
$lines = explode(PHP_EOL, $csvData);
$array = array();
foreach ($lines as $line) {
$array[] = str_getcsv($line, $delimiter);
}
return $array;
}
The problem here is Im using EOL to determine where a line ends, if the CSV file have any field with any end of line chars im getting errors.
Example:
Product_Name, "Description"
Product_Name, "Description"
Product_Name, "Description"
Product_Name, "Description"
This works ok, but if I have something like this:
Product_Name, "Description_line_1
Description_line_2"
Product_Name, "Description_line_1
Description_line_2"
Product_Name, "Description_line_1
Description_line_2"
The script will fail, is there any way I can improve the script in order to consider this or is better to use a regular expression to fix first the CSV before calling the sript?
If you want to save writing to a temporary file yourself you can use the memory stream.
private function _csvToArray($url, $delimiter=',')
{
$fp = fopen('php://memory', 'r+');
fwrite($fp, file_get_contents($url));
fseek($fp, 0);
$array = array();
while ($row = fgetcsv($fp, 0, $delimiter)) {
$array[] = $row;
}
fclose($fp);
return $array;
}
fgetcsv can handle EOL in fields if the field data is between enclosure characters.
private function _csvToArray($url, $delimiter=',', $enclosure='"')
{
$handle = fopen($url, 'r');
$array = array();
while($row = fgetcsv($handle, 0, $delimiter, $enclosure))
{
$array[] = $row;
}
fclose($handle);
return $array;
}
Something like this should work (havent properly tested the code):
$csv = array_map('str_getcsv', file($url), ',', '"');
I had an old code lying around which fixed this once for me... But remember... it's from way way back;
$url = 'file.csv';
$csv = array();
$csvContents = file_get_contents($url);
$lines = explode('"'."\n", trim($csvContents));
foreach($lines as $lineNumber => $line) {
$csv[$lineNumber] = array();
$fields = explode(',', $line);
foreach($fields as $field) {
$csv[$lineNumber][] = ltrim(rtrim($field, '"'), '"');
}
}

How can I parse a CSV into array with first value as key?

So I have a CSV file that looks like this:
12345, Here is some text
20394, Here is some more text
How can I insert this into an array that looks like so
$text = "12345" => "Here is some text",
"20394" => "Here is some more text";
This is what I currently had to get a single numerical based value on a one tier CSV
if ($handle = fopen("$qid", "r")) {
$csvData = file_get_contents($qid);
$csvDelim = "\r";
$qid = array();
$qid = str_getcsv($csvData, $csvDelim);
} else {
die("Could not open CSV file.");
}
Thanks for the replies, but I still see a potential issue. With these solutions, wouldn't the values store in this way:
$array[0] = 12345
$array[1] = Here is some text 20394
$array[2] = Here is some more text
If I tried this on the example csv above, how would the array be structured?
You can use fgetcsv() to read a line from a file into an array. So something like this:
$a = array();
$f = fopen(....);
while ($line = fgetcsv($f))
{
$key = array_shift($line);
$a[$key] = $line;
}
fclose($f);
var_dump($a);
Assuming that the first row in the CSV file contains the column headers, this will create an associative array using those headers for each row's data:
$filepath = "./test.csv";
$file = fopen($filepath, "r") or die("Error opening file");
$i = 0;
while(($line = fgetcsv($file)) !== FALSE) {
if($i == 0) {
$c = 0;
foreach($line as $col) {
$cols[$c] = $col;
$c++;
}
} else if($i > 0) {
$c = 0;
foreach($line as $col) {
$data[$i][$cols[$c]] = $col;
$c++;
}
}
$i++;
}
print_r($data);
If you are reading a file I can recommend using something like fgetcsv()
This will read each line in the CSV into an array containing all the columns as values.
http://at2.php.net/fgetcsv
$csv_lines = explode('\n',$csv_text);
foreach($csv_lines as $line) {
$csv_array[] = explode(',',$line,1);
}
edit - based on code posted after original question:
if ($handle = fopen("$qid", "r")) {
$csvData = file_get_contents($qid);
$csvDelim = "\r"; // assume this is the line delim?
$csv_lines = explode($csvDelim,$csvData);
foreach($csv_lines as $line) {
$qid[] = explode(',',$line,1);
}
} else {
die("Could not open CSV file.");
}
With your new file with two columns, $qid should become an array with two values for each line.
$csvDelim = ",";
$qid = str_getcsv($csvData, $csvDelim);
$text[$qid[0]] = $qid[1];

Categories