String parsing in PHP - php

I am trying to parse a string in PHP:
-father_name "John" -father_weight 44.50
-kid >name "Marko" >age 12
-kid >name "Sevda" >age 17
-kid >name "Nathan" >age 19
There are two main FORMS:
Attributes (such as -father, -weight, -kid)
Sub-Attributes (such as >name, >age)
Note: Attributes are NOT FIXED and NOT ALWAYS SEPERATED BY single space
And their VALUES have two types:
String (like "Marko")
Int or Decimal (like 12.00)
OUTPUT would be:
$array['attributes'] = array('father_name ','father_weight ');
$array['attributes']['kid'][] = array('name' => "Marko", 'age' => 12);
$array['attributes']['kid'][] = array('name' => "Sevda", 'age' => 17);
$array['attributes']['kid'][] = array('name' => "Nathan", 'age' => 19);
It should return FORMS (attrs and sub-attrs) and VALUES SEPARATELY.
How can I parse this line in PHP cleverly?
Last Note: Solution I found for this: YAML.

Try with this:
function parse_attributes($string, $separators = array('-','>'), $level = 0){
$attributes = explode($separators[$level], $string);
$attrs = array();
$ret_arr = array();
foreach($attributes as $attribute){
if(!empty($attribute)){
$ex_attr = explode(' ',$attribute);
if(!empty($ex_attr[1])){
if(count($separators) > $level && strpos($attribute, $separators[$level+1])){
$ret = parse_attributes($attribute, $separators, $level+1);
array_push($ret_arr, $ret);
}
if (empty($ret_arr))
$attrs[$ex_attr[0]] = str_replace('"', '', $ex_attr[1]);
else
$attrs[$ex_attr[0]] = $ret_arr;
}
}
}
return $attrs;
}
Using:
$returned = parse_attributes('-father_name "John" -father_weight 44.50 -kid >name "Marko" >age 12 -kid >name "Sevda" >age 17 -kid >name "Nathan" >age 19');
print_r($returned);
Returns:
Array
(
[father_name] => John
[father_weight] => 44.50
[kid] => Array
(
[0] => Array
(
[name] => Marko
[age] => 12
)
[1] => Array
(
[name] => Sevda
[age] => 17
)
[2] => Array
(
[name] => Nathan
[age] => 19
)
)
)
And using:
echo($returned['kid'][0]['name']);
Returns:
Marko
NOTE: You can specify more separator array items, an item for each attribute level you have.
Hope this helps.

$output = array();
$input = explode('-', $input);
foreach ($input as $attribute) {
$attribute = explode('>', $attribute);
if (count($attribute) == 1) {
$attribute = explode(' ', trim($sub_attribute), 2);
$output[$attribute[0]] = eval($attribute[1]);
} else {
$attribute_name = trim($attribute[0]);
if (!isset($output[$attribute_name]) {
$output[$attribute_name] = array();
}
$sub_attribute_output = array();
for ($i = 1; $i < count($attribute); $i++) {
$sub_attribute = explode(' ', trim($attribute[$i]), 2);
$sub_attribute_output[$sub_attribute[0]] = eval($sub_attribute[1]);
}
$output[$attribute_name][] = $sub_attribute_output;
}
}

Related

Smart explode or something other

I have array:
$array = [
'aaa 3',
'bbb 15',
'ccccc 3A',
'dddd 2412',
'eee fff 15',
'ggg 612',
'hhh iiiii 23B',
];
I would like receive:
$name = 'aaa'; $number = '3';
$name = 'bbb'; $number = '15';
$name = 'ccccc'; $number = '3A';
$name = 'dddd'; $number = '2412';
$name = 'eee'; $number = '15';
$name = 'ggg'; $number = '612';
$name = 'hhh iiiii'; $number = '23B';
So I do:
foreach ($array as $item) {
$expl = explode(' ', $item);
$name = $expl[0];
$number = $expl[1];
}
But this not working for eee fff 15 and hhh iiiii 23B, because these names has two parts. How is better way for this?
Use a regex:
<?php
$array = [
'aaa 3',
'bbb 15',
'ccccc 3A',
'dddd 2412',
'eee fff 15',
'ggg 612',
'hhh iiiii 23B',
];
$regex = '#(?<word>.+)\s(?<number>.+)#';
$results = [];
foreach ($array as $line) {
preg_match($regex, $line, $matches);
$results[$matches['word']] = $matches['number'];
}
var_dump($results);
2 capture groups, first is any characters .+, then a space \s, then any characters .+
Output:
array(7) { ["aaa"]=> string(1) "3" ["bbb"]=> string(2) "15" ["ccccc"]=> string(2) "3A" ["dddd"]=> string(4) "2412" ["eee fff"]=> string(2) "15" ["ggg"]=> string(3) "612" ["hhh iiiii"]=> string(3) "23B" }
See it working here: https://3v4l.org/t2tMd
You need to look at the size of the array and pick only the last for the number and the rest for the name...
foreach ($array as $item) {
$expl = explode(' ', $item);
$name = implode(" ", array_slice($expl,0,-1));
$number = $expl[count($expl)-1];
echo $name."=". $number.PHP_EOL;
}
Bit late to the party but I wanted to throw in my suggestion on how to do this.
If the $number you want is always at the end of the array, then it doesn't matter how big $name is
$newArray = array();
foreach ($array as $item) {
$expl = explode(' ', $item);
//get the size of the array
$last= count($expl)-1;
//get the final element in the array
$number = $expl[$last];
//remove the last element from array
unset($expl[$last]);
//glue it back together
$name = implode(" ",$expl);
//set the name + number in our array
$newArray[]=array('name' => $name,'number'=>$number);
}
print_r($newArray);
//Output:
/* Array (
[0] => Array (
[name] => aaa
[number] => 3
)
[1] => Array (
[name] => bbb
[number] => 15
)
[2] => Array (
[name] => ccccc
[number] => 3A
)
[3] => Array (
[name] => dddd
[number] => 2412
)
[4] => Array (
[name] => eee fff
[number] => 15
)
[5] => Array (
[name] => ggg
[number] => 612
)
[6] => Array (
[name] => hhh iiiii
[number] => 23B
)
)
*/
try this,
foreach ($array as $item) {
$expl = explode(' ', $item);
$division=array_pop($expl);
$name = $expl[0].' '.$expl[1];
$number = $division;
}

PHP reading data input from a text file

I have a text file which I must read, and use the data from.
3
sam 99912222
tom 11122222
harry 12299933
sam
edward
harry
How can I create an array of these strings in the following form?
array(
"name" => "number"
...
)
I tried this:
$handle = fopen("file.txt", "r");
fscanf($handle, "%d %d", $name, $number);
What then? No matter what I try, it only works for the first line.
sam 99912222
Added codes to have both types of output - ignoring and including the lines that don't have name-value pairs. Check them out below
This code goes through each line and gets only the ones that have both name and value (something[space]something)):
//$lines = ... each line of the file in an array
$vals = array();
foreach($lines as $v){
$tmp = explode(' ', $v);
if(count($tmp) > 1){
$vals[trim($tmp[0])] = trim($tmp[1]); // trim to prevent garbage
}
}
print_r($vals);
It will output this:
Array
(
[sam] => 99912222
[tom] => 11122222
[harry] => 12299933
)
See the code in action here.
If you need the values even if they didn't come in pairs, do it like this:
//$lines = ... each line of the file
$vals = array();
foreach($lines as $v){
$tmp = explode(' ', $v);
$name = '';
$number = '';
$tmp[0] = trim($tmp[0]);
if(count($tmp) > 1){
$name = $tmp[0];
$number = trim($tmp[1]);
}else{
if(is_numeric($tmp[0])){
$number = $tmp[0];
}else{
$name = $tmp[0];
}
}
$vals[] = array(
'name' => $name,
'number' => $number
);
}
print_r($vals);
And the output:
Array
(
[0] => Array
(
[name] =>
[number] => 3
)
[1] => Array
(
[name] => sam
[number] => 99912222
)
[2] => Array
(
[name] => tom
[number] => 11122222
)
[3] => Array
(
[name] => harry
[number] => 12299933
)
[4] => Array
(
[name] => sam
[number] =>
)
[5] => Array
(
[name] => edward
[number] =>
)
[6] => Array
(
[name] => harry
[number] =>
)
See the code in action here.
Data in file are inconsistent, best of is to use regex to identify what data you've got from each line.
$lines = file('file.txt'); // this will open file and split them into lines
$items = array();
foreach($lines as $line){
$name = null;
$number = null;
$nameFound = preg_match("|([A-Za-z]+)|", $line, $matches);
if($nameFound){
$name = $matches[0];
}
$numberFound = preg_match("|([0-9]+)|", $line, $matches);
if($numberFound){
$number = $matches[0];
}
$items[] = array('name' => $name, 'number' => $number);
}
Then in items you should find parsed data from file.
To make it just extract full format data just change lines with regex into one line like this:
$lines = file('file.txt'); // this will open file and split them into lines
$items = array();
foreach($lines as $line){
$userFound = preg_match("/([A-Za-z]+) ([0-9]+)/", $line, $matches);
if($userFound){
$items[$matches[1]] = $matches[2];
}
}
With the Algorithm below, you can simply parse each individual line of the Text-File Contents into an array with the 1st Word or Digit(s) on each line as the Key and the 2nd Word as the Value. When the 2nd word or group of words do not exist, a NULL is assigned to that Key. For re-usability, this algorithm has been encapsulated into a Function. Here you go:
<?php
function parseTxtFile($txtFile){
$arrTxtContent = [];
if(!file_exists($txtFile)){ return null;}
$strFWriteTxtData = file_get_contents($txtFile);
if(empty($strFWriteTxtData)){return null;}
$arrFWriteInfo = explode("\n", $strFWriteTxtData);
foreach($arrFWriteInfo as $iKey=>$lineData){
$arrWriteData = explode(", ", $lineData);
foreach($arrWriteData as $intKey=>$strKeyInfo){
preg_match("#(^[a-z0-9_A-Z]*)(\s)(.*$)#i", $strKeyInfo, $matches);
preg_match("#(^[a-z0-9_A-Z]*)(\s*)?$#i", $strKeyInfo, $matches2);
if($matches) {
list(, $key, $null, $val) = $matches;
if (!array_key_exists($key, $arrTxtContent)) {
$arrTxtContent[$key] = $val;
}else{
$iKey = $intKey + 1;
$key = $key . "_{$iKey}";
$arrTxtContent[$key] = $val;
}
}else if($matches2) {
list(, $key, $null) = $matches2;
if (!array_key_exists($key, $arrTxtContent)) {
$arrTxtContent[$key] = null;
}else{
$key = preg_match("#_\d+#", $key, $match)? $key . $match[0] : "{$key}_1";
$arrTxtContent[$key] = null;
}
}
}
}
return $arrTxtContent;
}
var_dump(parseTxtFile(__DIR__ . "/data.txt"));
Just call the function parseTxtFile($txtFile) passing it the path to your text File and it will return an Array that looks something like below:
array (size=7)
3 => null
'sam' => string '99912222' (length=8)
'tom' => string '11122222' (length=8)
'harry' => string '12299933' (length=8)
'sam_1' => null
'edward' => null
'harry_1' => null
Hope this could help a bit....
Cheers & Good-Luck ;-)

Php Array removing duplication and string conversion

hi i have output of an array as follow:
Array (
[0] => 66, 65, 64
[1] => 57
[2] => 66,23
[3] => 66
)
How can i remove duplication values and convert the collection into comma separated string? The unique output is 66,65,64,57,23. Thanks
Make use of array_unique() and array_reverse():
$array = Array (
0 => '66, 65, 64',
1 => '57',
2 => '66,23',
3 => '66',
);
$collection = array();
foreach($array as $numbers) {
$nums = explode(',', $numbers);
foreach($nums as $num) {
$collection[] = trim($num);
}
}
// unique and sort
$collection = array_unique($collection, SORT_NUMERIC);
// reverse it so that it can be descending order
$collection = array_reverse($collection);
print_r($collection);
which will output :
Array (
[0] => 66
[1] => 65
[2] => 64
[3] => 57
[4] => 23
)
you iterate through the array and add it to a final array by checking its values then implode to construct a string.
$array = Array (
0 => array(66, 65, 64),
1 => array(57),
2 => array(66,23),
3 => array( 66)
);
$final = array();
foreach ($array as $item) {
foreach ($item as $num) {
if (!in_array($num, $final)) $final[] = $num;
}
}
$str = implode(",", $final);
echo $str
well, the code is lil ugly...
$test = [
'0' => '66, 65',
'1' => '80', '66'
];
$temp = implode(',', array_map('trim', array_unique(explode(',', implode(',', $test)))));
print_r($test);
print_r($temp);
//output
Array (
[0] => 66, 65
[1] => 80
[2] => 66
)
66,65,80
Ok:
<?php
$array = array(
"66, 65, 64",
57,
"66,23",
66
);
function dosplit($a,$b) {
if (preg_match("/,/",$b)) {
$a = array_merge($a, preg_split('/\s*,\s*/', $b));
} else {
array_push($a, $b);
}
return $a;
}
$result = array_reduce($array, 'dosplit' ,array());
$array = array_unique($result);
The output is:
Array
(
[0] => 66
[1] => 65
[2] => 64
[3] => 57
[5] => 23
)
This might is useful for you:
$array = array(
"66, 65, 64 ",
"57",
"66,23",
"66",
);
echo "<pre>";
print_r($array);
//to make single line
foreach ($array as $val) {
$singleline.=$val . ",";
}
echo $singleline . "</br>";
//remove the "," end of the value
$endvlaue = rtrim($singleline, ",");
echo $endvlaue;
//make an array
$val = explode(",", $endvlaue);
echo "<pre>";
print_r($val);
echo "<pre>";
//make uniqu
$finalvalue = array_unique($val);
echo "<pre>";
//make , seperator
print_r(implode(",", $finalvalue));

Deleting redundant data inside an array

I have a problem, I have this result below and I want to remove the same timestamp.
Sample Result:
Array
(
[0] => [1341100800000, 0]
[1] => [1341100800000,85]
[2] => [1343779200000,54]
[3] => [1343779200000, 0]
)
Expecting Output
Array
(
[0] => [1341100800000,85]
[1] => [1343779200000,54]
)
I'm thinking of using explode then substr function to get the value. Here is what I came up so far..
$explode = array();
foreach($string_format as $key => $value) {
$explode[] = explode(',', substr($value, 1));
if((isset($explode[0]) && $explode[0][0] == $explode[1][0])) {
unset($explode[0]);
}
//print_r($explode);
}
wouldn't this be a good use of http://us2.php.net/manual/en/function.array-unique.php
Script:
foreach($string_format as $key => $value) {
$explode = explode(',', $value);
$unique[$explode[0]] = $value;
}
Input:
$string_format = array('0' => '1341100800000, 0',
'1' => '1341100800000,85',
'2' => '1343779200000,54',
'3' => '1343779200000, 0');
Output:
$unique =
Array
(
[1341100800000] => 1341100800000,85
[1343779200000] => 1343779200000, 0
)
This should work fine :)
$explode = array();
$timestmp = array();
foreach($string_format as $key => $value) {
$explode[$key] = explode(',', substr($value, 1));
if( in_array( $explode[$key][0], $timestmp)) {
unset ($explode[$key]);
} else {
$timestmp[]= $explode[$key][0];
}
}

Explode string in PHP that contain brackets and semicolon

Problem:
I have a string that looks like this:
[1=>2,3,4][5=>6,7,8][9=>10,11,12][13=>14,15][16=>17,18]
Question:
How can you get that string into this?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
I will try with:
$input = '[1=>2,3,4][5=>6,7,8][9=>10,11,12][13=>14,15][16=>17,18]';
$output = array();
preg_match_all('\[(\d+)=>([\d,]+)\]', $input, $matches);
foreach ($matches as $group) {
$output[$group[1])] = explode(',', $group[2]);
}
// and print result out:
foreach ( $output as $key => $val ) {
echo $key . '<br/>';
foreach ( $val as $v ) {
echo ' ' . $v . '<br/>';
}
}
This code:
$input = '[1=>2,3,4][5=>6,7,8][9=>10,11,12][13=>14,15][16=>17,18]';
$regex = '~\[(?P<keys>\d)+=>(?P<values>(?:\d+,?)+)\]~';
$result = array();
if (preg_match_all($regex, $input, $matches)) {
foreach ($matches['keys'] as $key => $value) {
$result[$value] = explode(',', $matches['values'][$key]);
}
}
print_r($result);
Results to this:
Array
(
[1] => Array
(
[0] => 2
[1] => 3
[2] => 4
)
[5] => Array
(
[0] => 6
[1] => 7
[2] => 8
)
[9] => Array
(
[0] => 10
[1] => 11
[2] => 12
)
[3] => Array
(
[0] => 14
[1] => 15
)
[6] => Array
(
[0] => 17
[1] => 18
)
)
$str = "[1=>2,3,4][5=>6,7,8][9=>10,11,12][13=>14,15][16=>17,18]";
$str = explode("]", $str);
$finalResult = array();
foreach ($str as $element) {
if (!empty($element)) {
$element = substr($element, 1);
$element = explode("=>", $element);
// element[0] contains the key
$element[1] = explode(",", $element[1]);
$finalResult[$element[0]] = $element[1];
}
}
print_r($finalResult);
<?php
$str = "[1=>2,3,4][5=>6,7,8][9=>10,11,12][13=>14,15][16=>17,18]";
$parts1 = explode("][",$str);
$parts1[0]=str_replace("[","",$parts1[0]);
$parts1[count($parts1)-1]=str_replace("]","",$parts1[count($parts1)-1]);
foreach($parts1 as $k=>$v){
$parts2[]=explode("=>",$v);
}
foreach($parts2 as $k=>$v){
echo "<div>".$v[0]."</div>";
foreach(explode(",",$v[1]) as $key=>$value){
echo "<div style='margin-left:20px'>".$value."</div>";
}
}
Output Would be
Using only str_replace():
$dict = array(
'=>' => "\n\t",
',' => "\n\t",
'][' => "\n",
'[' => '',
']' => '',
);
echo str_replace(array_keys($dict), array_values($dict), $str);
Will give the result you want.

Categories