Parsing Python array in PHP - php

I have a Python script running on my server that creates a 2D list like so:
[['Header1', 'Header2', 'Header3'], ['2012-09-10 00:11:00', '61.3', '57.0'], ...]
I pass this back to the PHP script which is running my webpage. Here's the PHP I'm currently using to get the array. I get the rows, but obviously with an unwanted [[ at the start and ]] at the end.
exec("python weatherdata.py $stationID $startdate $enddate", $pyoutput);
$vars = explode("], [", $pyoutput[0]);
For the sake of explaining what I actually want to do, since there's bound to be a "proper" solution (I'm not at all familiar with PHP), what I want to do is adapt the code from here which download a CSV file to the user, but uses mySQL to populate it. The set-up part here works fine.
Edited in response to Jack's answer below
// Commented out my working parsing part
// remove the start and end square braces then split into rows
//$output = str_replace("[[","",$pyoutput);
//$output = str_replace("]]","",$output);
//$rows = explode("], [", $output[0]);
// output headers so that the file is downloaded rather than displayed
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename='data.csv');
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
foreach (preg_split('/],\s*\[/', trim($pyoutput, '[]')) as $row) {
$data= preg_split("/',\s*'/", trim($row, "'"));
fputcsv($data);
}
// Commented out my working write to CSV part
// write rows
//foreach ($rows as $row){
// $row = str_replace("'","",$row);
// $row = explode(",", $row);
// fputcsv($output, $row);
//}

Not sure whether this is viable for you, but since PHP 5.4 it supports the short array syntax, e.g. [1, 2, 3] instead of array(1, 2, 3).
So, you could just use evil ... I mean eval():
$vars = eval(`python weatherdata.py $stationID $startdate $enddate`);
Otherwise, if the array syntax is always in that format, just break it apart with preg_split(), first on square brackets and then on single quotes:
foreach (preg_split('/],\s*\[/', trim($s, '[]')) as $row) {
$data = preg_split("/',\s*'/", trim($row, "'"));
print_r($data);
}
Output:
Array
(
[0] => Header1
[1] => Header2
[2] => Header3
)
Array
(
[0] => 2012-09-10 00:11:00
[1] => 61.3
[2] => 57.0
)

Related

How to read tab sepereated values in PHP using fscanf

Recently I was practicing problems in Hackearth and I was unable to scan tab-separated values.
Ex(Inputs): 12 3 6 1
The input is treated as a file, it seems, because fscanf is used to read it.
I was trying to scan it using while loop like this:
$arr = [];
$i = 0;
while($i < 4){
fscanf(STDIN, "%s\t", $a);
$arr[] = $a;
$i++;
}
But when I am printing $arr like:
print_r($arr);
It shows like this:
Array
(
[0] => 12
[1] => 12
[2] => 12
[3] => 12
)
I checked this problem but unable to solve my problem.
How can I scan all the numbers using a loop and put it in an array?
According to the documentation:
Each call to fscanf() reads one line from the file.
So you can't call fscanf() in a loop to read each number from the same line. The second iteration tries to read the next line, but there isn't one.
You can use fgets() to read a whole line, then use explode() to split it into an array at the delimiters:
$line = fgets(STDIN);
$line = rtrim($line); // remove the newline
$arr = explode("\t", $line);
Or use fgetcsv() to do this in one step:
$arr = fgetcsv(STDIN, 0, "\t");

PHP writting 'null' for JSON file written by Python

I am trying to send JSON information from Python to PHP through a JSON file data.json, based on the content of the Stack Overflow question/answer here. I am running this code all on an Apache web server on Raspberry Pi 3.
Here is my code:
Python
import sys, json, random # I know I don't need sys and random to run this, but I was using these in my previous code.
data = {'fruit':['oranges', 'apples', 'peaches'], 'age':12}
with open('data.json', 'w') as outfile:
json.dump(data, outfile)
When run, this program worked fine and exited with code 0.
JSON file
{"age": 12, "fruit": ["oranges", "apples", "peaches"]}
As you can see, my Python worked perfectly and the output is identical to the data variable in my python code. On second thought, the order is backward, although I don't think this matters.
PHP
Now, this is where the problem is:
<?php
$string = file_get_contents("data.json");
$json_a = json_decode($string, true);
$arr = array();
foreach ($json_a as $key) {
array_push($arr,json_decode($key[0],true));
}
echo json_encode($arr);
?>
When run, the program exited with code 0 but outputed:
[null,null]
Does anyone have an idea why this is, or is this just the way JSON works?
The original code with issues:
<?php
$string = file_get_contents("data.json");
$json_a = json_decode($string, true);
$arr = array();
foreach ($json_a as $key) {
// No need to use json_decode again
// as it is already converted to an array
// by the inital json decode statement
array_push($arr,json_decode($key[0],true));
}
echo json_encode($arr);
?>
Pretty printed PHP Array which is stored inside $json_a:
Array
(
[age] => 12
[fruit] => Array
(
[0] => oranges
[1] => apples
[2] => peaches
)
)
The problem:
In the original script, json_decode was used on an already decoded variable/array which returned nothing and hence null was appended to your list.
Code walkthrough:
During the first iteration of the foreach loop,
$key will have the value 12 - which is a string
During the second iteration of the foreach loop,
$key will have the value - which is an Array
Array
(
[0] => oranges
[1] => apples
[2] => peaches
)
The corrected code for printing all the fruits:
<?php
$string = file_get_contents("data.json");
$json_a = json_decode($string, true);
$arr = array();
foreach ($json_a['fruit'] as $key) {
array_push($arr,$key);
}
echo json_encode($arr);
?>
The above snippet returns ["oranges","apples","peaches"]

How can I remove duplicated lines in a file using PHP (including the "original' one)?

Well, my question is very simple, but I didn't find the proper answer in nowhere. What I need is to find a way that reads a .txt file, and if there's a duplicated line, remove ALL of them, not preserving one. For example, in a .txt contains the following:
1234
1233
1232
1234
The output should be:
1233
1232
Because the code has to delete the duplicated line, all of them. I searched all the web, but it always point to answers that removes duplicated lines but preserve one of them, like this, this or that.
I'm afraid that the only way to do this is to read the x line and check the whole .txt, if it finds an equal result, delete, and delete the x line too. If not, change to the next line. But the .txt file I'm checking has 50 milions lines (~900Mb), I don't know how much memory I need to do this kind of task, so I appreciate some help here.
Read the file line by line, and use the line contents as the key of an associative array whose values are a count of the number of times the line appears. After you're done, write out all the lines whose value is only 1. This will require as much memory as all the unique lines.
$lines = array();
$fd = fopen("inputfile.txdt", "r");
while ($line = fgets($fd)) {
$line = rtrim($line, "\r\n"); // ignore the newline
if (array_key_exists($line, $lines)) {
$lines[$line]++;
} else {
$lines[$line] = 1;
}
}
fclose($fd);
$fd = fopen("outputfile.txt", "w");
foreach ($lines as $line => $count) {
if ($count == 1) {
fputs($fd, "$line" . PHP_EOL); // add the newlines back
}
}
I doubt there is one and only one function that does all of what you want to do. So, this breaks it down into steps...
First, can we load a file directly into an array? See the documentation for the file command
$lines = file('mytextfile.txt');
Now, I have all of the lines in an array. I want to count how many of each entry I have. See the documentation for the array_count_values command.
$counts = array_count_values($lines);
Now, I can easily loop through the array and delete any entries where the count>1
foreach($counts as $value=>$cnt)
if($cnt>1)
unset($counts[$value]);
Now, I can turn the array keys (which are the values) into an array.
$nondupes = array_keys($counts);
Finally, I can write the contents out to a file.
file_put_contents('myoutputfile.txt', $nondupes);
I think I have a solution far more elegant:
$array = array('1', '1', '2', '2', '3', '4'); // array with some unique values, some not unique
$array_count_result = array_count_values($array); // count values occurences
$result = array_keys(array_filter($array_count_result, function ($value) { return ($value == 1); })); // filter and isolate only unique values
print_r($result);
gives:
Array
(
[0] => 3
[1] => 4
)

Converting CSV rows string into array

I am using an API that returns a CSV string as the following:
Date,Open,High,Low,Close,Volume,Adj Close 2014-06-13,3.10,3.30,3.10,3.30,6638300,3.30
I was wondering if there is an easy way to convert this CSV string to an associative array? I am familiar with working with a CSV file, but not sure what to do with a CSV file string response. I am trying to avoid writing the response to a file, just so I can read it back.
Note, writing this response to a CSV file would result in two rows and seven columns.
If the line terminator is \r\n, then first you need to explode them thru that. Then you can proces from there. Consider this example:
$data = explode("\r\n", $csv_string);
// get the headers first
$headers = array_map('trim', explode(',', array_shift($data)));
$new_data = array();
// get the values and use array combine to use the headers as keys for associative array
foreach($data as $values) {
$pieces = explode(',', $values);
// i just assigned it in an array, since we dont know how many lines of data you will receive
$new_data[] = array_combine($headers, $pieces);
}
$new_data should yield something like this:
Array
(
[0] => Array
(
[Date] => 2014-06-13
[Open] => 3.10
[High] => 3.30
[Low] => 3.10
[Close] => 3.30
[Volume] => 6638300
[Adj Close] => 3.30
)
)
Or just the usual way of handling csv strings. Use str_getcsv().
$data = str_getcsv($csv_string, "\r\n");
$headers = explode(',', array_shift($data));
$data = array_combine($headers, explode(',',reset($data)));
As others have mentioned, str_getcsv() is your friend and is an easy method to convert a CSV string into an array. This function will return an array of results. If you'd like to make it an associative array, use array_combine().
Honestly, though -- str_getcsv() may be overkill. Consider this method using explode():
// so given this string returned by the API
$api_s = "Date,Open,High,Low,Close,Volume,Adj Close\r\n2014-06-13,3.10,3.30,3.10,3.30,6638300,3.30";
// split on carriage return & line feed into two strings
$api_r = explode("\r\n", $api_s);
// split keys and values by comma
$keys = explode(',', $api_r[0]);
$vals = explode(',', $api_r[1]);
// construct associative array
$my_assoc_r = array_combine($keys, $vals);

Create variable from print_r output [duplicate]

This question already has answers here:
How create an array from the output of an array printed with print_r?
(11 answers)
Closed 10 years ago.
How can i create variable from it's print_r output ? In other words, i'd like to know if something similar to my fictive var_import function exists in php ? var_import would be the inverse of var_export
He is a use case:
$a = var_import('Array ( [0] => foo [1] => bar )');
$output = var_export($a);
echo $output; // Array ( [0] => foo [1] => bar )
If such a function does not exist, is there a tool (or online tool) to do this ?
I am also interested to do the same with var_dump output.
EDIT: The variable is only available as a print_r output (string). To clarify what i need, imagine the folowing situation: someone posts a some sample on the internet somewhere with a print_r output. To test his code, you need to import his print_r variable into your code. This is an example where var_import would be usefull.
Amusingly the PHP manual contains an example that tries to recreate the original structure from the print_r output:
print_r_reverse()
http://www.php.net/manual/en/function.print-r.php#93529
However it does depend on whitespace being preserved. So you would need the actual HTML content, not the rendered text to pipe it back in.
Also it doesn't look like it could understand anything but arrays, and does not descend. That would be incredibly difficult as there is no real termination marker for strings, which can both contain newlines and ) or even [0] and => which could be mistaken for print_r delimiters. Correctly reparsing the print_r structure would be near impossible even with a recursive regex (and an actual parser) - it could only be accomplished by guesswork splitting like in the code linked above.. (There are two more versions there, maybe you have to try them through to find a match for your specific case.)
Why don't you use var_export instead ?
var_export(array(1, 2, 3)); // array(1, 2, 3)
You can import var_export's output with eval(), however I would recommend you to avoid this function as much as possible.
The following functions are better for exporting and importing variables:
serialize() and unserialize():
$string = serialize(array(1, 2, 3));
$array = unserialize($string); // array(1, 2, 3);
Or json_encode() and json_decode():
$string = json_encode(array(1, 2, 3));
$array = json_decode($string);
You can wrap it in an output buffer:
ob_start();
print_r(array(1,2,3));
$arr = ob_get_clean();
echo $arr;
Ok so I misunderstood the first question. I think I have another solution which actually does answer your question:
<?php
$ar = array('foo','bar');
$p = print_r($ar, true);
$reg = '/\[([0-9]+)\] \=\> ([a-z]+)/';
$m = preg_match_all($reg, $p, $ms);
$new_ar = $ms[2];
echo "Your wanted result:\n";
print_r($new_ar);
If you want to import a var_export()'s variable, you can run the eval() function.
Or if you save the contents into a file (with a return statement), you can use the return value of include() or require().
But I would rather use serialize() and unserialize() or json_encode() and json_decode().
define('EXPORT_JSON', 1);
define('EXPORT_SERIALIZE', 2);
function exportIntoFile($var, $filename, $method=EXPORT_JSON)
{
if ( $method & EXPORT_JSON )
file_put_contents( $filename, json_encode($var) );
else if ($method & EXPORT_SERIALIZE)
file_put_contents( $filename, serialize($var) );
}
function importFromFile($filename, $method=EXPORT_JSON)
{
if ( $method & EXPORT_JSON )
return json_decode( file_get_contents($filename) );
else if ($method & EXPORT_SERIALIZE)
return unserialize( file_get_contents($filename) );
}
I'm not good at regex to code the final trash removal. Here is how far I could get though:
$str = 'Array ( [0] => foo [1] => bar [2] => baz)';
$t1 = explode('(', $str);
$t2 = explode(')', $t1[1]);
$t3 = explode(' => ', $t2[0]);
unset($t3[0]);
print_r($t3);
output:
Array
(
[1] => foo [1]
[2] => bar [2]
[3] => baz
)

Categories