Keep text within quotation intact, while splitting text - php

I need the data in the string [$str] that is within quotes to not split.
In this case, "Accounting company" should be kept in one string, not spread.
<?php
$str =
'#PROGRAM "Accounting company" 98.2
#GENERATED 2020715 "SE"';
$data = explode("\n", $str);
foreach($data as &$value){
$value = preg_split("/\s+/", $value);
}
var_dump($data);
Result:
array(2) {
[0]=>
array(4) {
[0]=>
string(8) "#PROGRAM"
[1]=>
string(11) ""Accounting" // Unwanted split
[2]=>
string(8) "company"" // Unwanted split
[3]=>
string(4) "98.2"
}
[1]=>
&array(4) {
[0]=>
string(0) ""
[1]=>
string(10) "#GENERATED"
[2]=>
string(7) "2020715"
[3]=>
string(4) ""SE""
}
}
Wanted result:
array(2) {
[0]=>
array(4) {
[0]=>
string(8) "#PROGRAM"
[1]=>
string(18) ""Accounting company"
[2]=>
string(4) "98.2"
}
[1]=>
&array(4) {
[0]=>
string(0) ""
[1]=>
string(10) "#GENERATED"
[2]=>
string(7) "2020715"
[3]=>
string(4) ""SE""
}
}

You could use a SKIP FAIL pattern to skip matching values from an opening till closing double quote and then match 1+ horizontal whitespace chars to split on
"[^"]*"(*SKIP)(*FAIL)|\h+
Regex demo
$str =
'#PROGRAM "Accounting company" 98.2
#GENERATED 2020715 "SE"';
$data = explode("\n", $str);
foreach($data as &$value){
$value = preg_split("/\"[^\"]*\"(*SKIP)(*FAIL)|\h+/", $value);
}
print_r($data);
Output
Array
(
[0] => #PROGRAM
[1] => "Accounting company"
[2] => 98.2
)
Array
(
[0] =>
[1] => #GENERATED
[2] => 2020715
[3] => "SE"
)
If you don't want the empty entry in the second array, you could use the PREG_SPLIT_NO_EMPTY flag:
$value = preg_split("/\"[^\"]*\"(*SKIP)(*FAIL)|\h+/", $value, -1, PREG_SPLIT_NO_EMPTY);
Php demo

Here a solution without regex
$str =
'#PROGRAM "Accounting company" 98.2
#GENERATED 2020715 "SE"';
$quoted = false;
$index = 0;
$data = [];
$rows = explode("\n", $str);
foreach($rows as $row) {
$temp = [];
for ($i = 0; $i < strlen($row); $i++) {
if ($row[$i] === "\"") $quoted = !$quoted;
if ($row[$i] === " " && !$quoted) {
$index++;
continue;
}
$temp[$index] = ($temp[$index] ?? "") . $row[$i];
}
$data[] = array_values($temp);
}
var_dump($data);
Result
array(2) {
[0]=>
array(3) {
[0]=>
string(8) "#PROGRAM"
[1]=>
string(20) ""Accounting company""
[2]=>
string(4) "98.2"
}
[1]=>
array(3) {
[0]=>
string(10) "#GENERATED"
[1]=>
string(7) "2020715"
[2]=>
string(4) ""SE""
}
}
Demo
Still figuring out a regex solution though :)
In case you want to keep the empty element at [1][0]: Demo

Related

Sort preg_match_all by named group size

I wrote a regular expression that parses a JS file and returns all the named functions and breaks it up into 3 parts, you can see it in action here: https://regex101.com/r/sXrHLI/1
I am analyzing the results and hoping to sort by the string length of the functionBody but I can't figure out how to do it.
Here is how I am capturing it:
$js = file_get_contents('scripts.js');
$regex = "/function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+})/";
preg_match_all($regex, $js, $jsFunctions);
dd($jsFunctions);
This spits out an array like this:
array(7) {
[0]=>
array(3) {
[0]=>
string(54) "function smallFunction(arg) {
BodyofSmallFunction
}"
[1]=>
string(62) "function mediumFunction(arg, arg2) {
BodyofMediumFunction
}"
[2]=>
string(80) "function largeFunction(arg, arg2, arg3=4) {
BodyofLargeFunction, extra text
}"
}
["functionName"]=>
array(3) {
[0]=>
string(13) "smallFunction"
[1]=>
string(14) "mediumFunction"
[2]=>
string(13) "largeFunction"
}
[1]=>
array(3) {
[0]=>
string(13) "smallFunction"
[1]=>
string(14) "mediumFunction"
[2]=>
string(13) "largeFunction"
}
["functionArguments"]=>
array(3) {
[0]=>
string(3) "arg"
[1]=>
string(9) "arg, arg2"
[2]=>
string(17) "arg, arg2, arg3=4"
}
[2]=>
array(3) {
[0]=>
string(3) "arg"
[1]=>
string(9) "arg, arg2"
[2]=>
string(17) "arg, arg2, arg3=4"
}
["functionBody"]=>
array(3) {
[0]=>
string(26) "{
BodyofSmallFunction
}"
[1]=>
string(27) "{
BodyofMediumFunction
}"
[2]=>
string(38) "{
BodyofLargeFunction, extra text
}"
}
[3]=>
array(3) {
[0]=>
string(26) "{
BodyofSmallFunction
}"
[1]=>
string(27) "{
BodyofMediumFunction
}"
[2]=>
string(38) "{
BodyofLargeFunction, extra text
}"
}
}
Now I want to sort by the functionBody size (they already appear sorted, but are really just in the order I had them in) but none of the code examples I can find using array_multisort or array_map seems to quite fit my array that PHP automatically builds. I would have loved to have had them in more of a consolidated tree format, but that wasn't my choice.
function sort_by_length($arrays) {
$lengths = array_map('count', $arrays);
asort($lengths);
$return = array();
foreach(array_keys($lengths) as $k)
$return[$k] = $arrays[$k];
return $return;
}
I was able to figure it out using a method described here: https://www.codepunker.com/blog/3-solutions-for-multidimensional-array-sorting-by-child-keys-or-values-in-PHP
$js = file_get_contents('scripts.js');
$regex = "/function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+})/";
preg_match_all($regex, $js, $jsFunctions);
$num_results = count($jsFunctions[3]);
function sortRegex(){
global $jsFunctions, $num_results;
for( $j=0; $j <= $num_results; $j++){
unset($jsFunctions[$j]);
if ( strlen($jsFunctions["functionBody"][$j]) < strlen($jsFunctions["functionBody"][$j-1]) ){
$functionBody = $jsFunctions["functionBody"][$j];
$jsFunctions["functionBody"][$j] = $jsFunctions["functionBody"][$j-1];
$jsFunctions["functionBody"][$j-1]=$functionBody;
$functionName = $jsFunctions["functionName"][$j];
$jsFunctions["functionName"][$j] = $jsFunctions["functionName"][$j-1];
$jsFunctions["functionName"][$j-1]=$functionName;
$functionArguments = $jsFunctions["functionArguments"][$j];
$jsFunctions["functionArguments"][$j] = $jsFunctions["functionArguments"][$j-1];
$jsFunctions["functionArguments"][$j-1]=$functionArguments;
sortRegex();
}
}
}
sortRegex();
You could now loop over it again and combine the items into a nested tree format if you wanted to.
$refinedJS = array();
for( $j=0; $j < $num_results; $j++){
$refinedJS[$j]= array(
"functionName"=>$jsFunctions["functionName"][$j],
"functionArguments"=>$jsFunctions["functionArguments"][$j],
"functionBody"=>$jsFunctions["functionBody"][$j]
);
}
print_r($refinedJS);
This will bring back the results like this:
Array
(
[0] => Array
(
[functionName] => smallFunction
[functionArguments] => arg
[functionBody] => {
BodyofSmallFunction
}
)
[1] => Array
(
[functionName] => mediumFunction
[functionArguments] => arg, arg2
[functionBody] => {
BodyofMediumFunction
}
)
[2] => Array
(
[functionName] => largeFunction
[functionArguments] => arg, arg2, arg3=4
[functionBody] => {
BodyofLargeFunction, extra text
}
)
)

Count multidimensional array

I have my main array:
array(6) {
[1]=> array(3) {
[0]=> string(15) "Extension"
[1]=> int(1)
[2]=> string(6) "3,00 "
}
[2]=> array(3) {
[0]=> string(32) "Physics "
[1]=> string(1) "1"
[2]=> string(6) "3,00 "
}
[3]=> array(3) {
[0]=> string(31) "Physics "
[1]=> int(1)
[2]=> string(6) "6,00 "
}
[4]=> array(3) {
[0]=> string(34) "Desk"
[1]=> int(4)
[2]=> string(8) "127,00 "
}
[5]=> array(3) {
[0]=> string(18) "assistance"
[1]=> int(1)
[2]=> string(7) "12,50 "
}
[6]=> array(3) {
[0]=> string(15) "Extension"
[1]=> int(1)
[2]=> string(6) "3,00 "
}
}
My expected output is:
Extension 2
Physics 2
Desk 1
Assistance 1
The result must be in an resultarray
How can I do? I tried with array_count_values function but don't work.
How can I stock answear:
I tried this code but It doesn't work
$tabrecap = array();
foreach($counts as $key=>$value){
//echo $key." qte".$value;
$tabrecap = array ($key,$value,$valueOption);
}
As you asked in comment,Please try this:-
<?php
$array = array( '1'=> array('0'=>"Extension", '1'=> 1, '2'=>"3,00 " ), '2'=> array('0'=>"Physics",'1'=>"1","3,00 " ),'3'=> array('0'=>"Physics",'1'=>1,"6,00 "),'4'=> array('0'=>"Desk",'1'=>4,"127,00 "),'5'=> array('0'=>"assistance",'1'=>1,"12,50 " ),'6'=> array('0'=>"Extension",'1'=>1,"3,00 "));
$count = array();
$i = 0;
foreach ($array as $key=>$arr) {
// Add to the current group count if it exists
if (isset($count[$i][$arr[0]])) {
$count[$i][$arr[0]]++;
}
else $count[$i][$arr[0]] = 1;
$i++;
}
print_r($count);
?>
Output:- https://eval.in/379176
Looping is the answer.
<?php
// untested
$counts = Array();
foreach( $array as $subArray ){
$value = $subArray[0];
$counts[ $value ] = ( isset($counts[ $value ]) )
? $counts[ $value ] + 1
: 1;
}
var_dump( $counts);
Just make a loop and use first item of each array as key :
$array = array(
array("Extension", 1, "3,00"),
array("Physics", "1", "3,00"),
array("Physics", 1, "6,00 ")
);
$count = array();
foreach($array as $a)
$count[$a[0]]++;
var_dump($count); // array(2) { ["Extension"]=> int(1) ["Physics"]=> int(2) }

Split Values in Array Using Explode to form Multidimensional Array

I am new to PHP so be kind. :)
I have a 3 deep array. Something like this:
Array(5) {
[0]=> array(5) {
[0]=> string(0) ""
[1]=> string(21) "0,245.19000000,864432"
[2]=> string(21) "1,245.26000000,864432"
[3]=> string(21) "2,245.49000000,864432"
[4]=> string(21) "4,245.33000000,864432"
}
[1]=> array(5) {
[0]=> string(0) ""
[1]=> string(21) "0,245.19000000,864453"
[2]=> string(21) "1,245.26000000,864453"
[3]=> string(21) "2,245.49000000,864453"
[4]=> string(21) "4,245.33000000,864453"
}
}...
I want to explode the inner string by commas ("2,245.49000000,864453") so the arrays becomes 4 deep like so:
Array(5) {
[0]=> array(5) {
[0]=> string(0) ""
[1]=> array (3)
[0]=> "0"
[1]=> "245.19000000"
[2]=> "864432"
[2]=> array (3)
[0]=> "1"
[1]=> "245.26000000"
[2]=> "864432"
[3]=> array (3)
[0]=> "3"
[1]=> "245.49000000"
[2]=> "864432"
[4]=> array (3)
[0]=> "4"
[1]=> "245.3000000"
[2]=> "864432"
[4]=> array (3)
[0]=> "5"
[1]=> "245.3300000"
[2]=> "864432"
}
}
...
So far I have:
$done = array();
for ($i = 0; $i<=count($chunks); $i++) { //loops to get size of each 2d array
$r = count($chunks[$i]);
for ($c = 0; $c<=count($chunks[$r]); $c++) { //loops through 3d array
$arrayparts = $chunks[$i][$c];
$done[] = explode(",", $arrayparts); //$arrayparts is 3d array string that is exploded each time through loop
}
}
I think this code should work but when I var_dump nothing prints?
Can someone help me learn?
Thanks!
Suggested:
$chunks is 3d array
foreach($chunks as $innerArray) {
$result[] = array_map(function($v){
return explode(",", $v);
}, $innerArray);
}
Don't make it complicated, just use this:
(Here I go through each innerArray with a foreach loop and then I go through all values with array_map() and explode it and return it to the results array)
<?php
foreach($arr as $innerArray) {
$result[] = array_map(function($v){
return explode(",", $v);
}, $innerArray);
}
print_r($result);
?>
This uses array_map() two times. Maybe a better way but I'm on beer three:
$result = array_map(function($v){
return array_map(function($v){ return explode(',', $v); }, $v);
}, $array);

Combining arrays - PHP

I have an array like:
print_r($arr);
array(2) {
["'type'"]=>
array(3) {
[0]=>
string(17) "tell" // <----
[1]=>
string(6) "mobile" // <----
[2]=>
string(6) "address" // <----
}
["'value'"]=>
array(3) {
[0]=>
string(11) "+00.0000000" // tell
[1]=>
string(11) "12345678" // mobile
[2]=>
string(11) "Blah SQ." // address
}
}
I want a final string like:
tell = +00.0000000<br />mobile = 12345678<br />address = Blah SQ.
Now it's been more than an hour I'm struggling with this but no results yet, anyone could help me with this? I would appreciate anykind of help.
Thanks
=======================================
What I have tried:
$arr is an array so I did:
foreach($arr as $values){
// here also $values is an array, so I needed another foreach to access to items:
$i = 0;
foreach($values as $items){
// now making the final output
#$output.= $items['type'][$i] . '=' . $items['value'][$i] . '<br />';
$i++;
}
}
I'd go for array_combine(). Basically it does what you request:
$yourArray = [
"type" => ["tell", "mobile", "address"],
"value" => ["+00.0000000", "12345678", "Blah SQ."]
];
$combined = array_combine($yourArray["type"], $yourArray["value"]);
will be
$combined = [
"tell" =>"+00.0000000",
"mobile" =>"12345678",
"address" =>"Blah SQ."
];
Lastly, you can iterate through that array and then join the values:
$finalArray=array();
foreach($combined as $type=>$value)
$finalArray[]="$type=$value";
$string = join("<br/>", $finalArray); // Will output tell=+00.000000<br/>mobile=12345678<br/>address=Blah SQ.
It's not the fastest method but you'll learn quite a bit about arrays.
EDIT (using array_combine by #Dencker)
foreach($arr as $values) {
// here also $values is an array, so I needed another foreach to access to items:
$v = array_combine($values["'type'"], $values["'value'"]);
foreach($v as $key => $val) {
// now making the final output
$output.= $key . '=' . $val . '<br />';
}
}
Try this
$arr = array(
array(
"'type'" => array('tell', 'mobile', 'address'),
"'value'" => array('+00000', '123123', 'foo')
),
array(
"'type'" => array('tell', 'mobile', 'address'),
"'value'" => array('+10000', '123123', 'bar')
),
array(
"'type'" => array('tell', 'mobile', 'address'),
"'value'" => array('+20000', '123123', 'foobar')
),
);
var_dump($arr);
$output = '';
foreach($arr as $values) {
// here also $values is an array, so I needed another foreach to access to items:
$i = 0;
foreach($values as $items) {
// now making the final output
$output.= $values["'type'"][$i] . '=' . $values["'value'"][$i] . '<br />';
$i++;
}
}
echo $output;
You were referencing the other array in the second loop.
=============================================================
EDIT:
var_dump($arr);
array(3) {
[0]=> array(2) {
["type"]=> array(3) {
[0]=> string(4) "tell"
[1]=> string(6) "mobile"
[2]=> string(7) "address"
}
["value"]=> array(3) {
[0]=> string(6) "+00000"
[1]=> string(6) "123123"
[2]=> string(3) "foo"
}
}
[1]=> array(2) {
["type"]=> array(3) {
[0]=> string(4) "tell"
[1]=> string(6) "mobile"
[2]=> string(7) "address"
}
["value"]=> array(3) {
[0]=> string(6) "+10000"
[1]=> string(6) "123123"
[2]=> string(3) "bar"
}
}
[2]=> array(2) {
["type"]=> array(3) {
[0]=> string(4) "tell"
[1]=> string(6) "mobile"
[2]=> string(7) "address"
}
["value"]=> array(3) {
[0]=> string(6) "+20000"
[1]=> string(6) "123123"
[2]=> string(6) "foobar"
}
}
}
OUTPUT:
tell=+00000
mobile=123123
tell=+10000
mobile=123123
tell=+20000
mobile=123123

How to find strings and add these string to an array

Anyone please help me..
$description = "This is product description. Quality is good. Title:title Price:1000 Size:XL, Medium, Small Color:red, green, blue. Any one can buy freely. ";
I wanna find "Title:", "Price:", "Size:" and "Color:" from that string and I want to add those values in an array.
My desired output is:
$new_desc = array(
'title'=>'title',
'price'=>1000,
'size'=>array(
[0]=>'XL',
[1]=>'Medium',
[2]=>'Small',
),
'color'=>array(
[0]=>'red',
[1]=>'green',
[2]=>'blue',
),
);
Thanks a lot!!!
Using preg_match_all, you can find you your identifiers (Price, Size ...) and their Values. You then just have to alter that to fit your array form.
Read up on preg_match_all and Regular Expressions.
<?php
$string = "This is product description. Quality is good. Title:title Price:1000 Size:XL, Medium, Small Color:red, green, blue. Any one can buy freely. ";
preg_match_all('/([^ ]{1,}):(([0-9a-z]{1,}|([0-9a-z,]{1,})( ))+)/i', $string, $matches);
var_dump($matches);
So this gives you:
array(6) {
[0]=>
array(4) {
[0]=>
string(11) "Title:title"
[1]=>
string(10) "Price:1000"
[2]=>
string(22) "Size:XL, Medium, Small"
[3]=>
string(22) "Color:red, green, blue"
}
[1]=>
array(4) {
[0]=>
string(5) "Title"
[1]=>
string(5) "Price"
[2]=>
string(4) "Size"
[3]=>
string(5) "Color"
}
[2]=>
array(4) {
[0]=>
string(5) "title"
[1]=>
string(4) "1000"
[2]=>
string(17) "XL, Medium, Small"
[3]=>
string(16) "red, green, blue"
}
[3]=>
array(4) {
[0]=>
string(5) "title"
[1]=>
string(4) "1000"
[2]=>
string(5) "Small"
[3]=>
string(4) "blue"
}
[4]=> [...]
}
if you iterate over the first set of matches from this array, you can create your desired output easily using stripos to find occurances of , and explode to generate arrays from your , seperated values.
$new_desc = array();
foreach ($matches[1] as $index => $identifier) {
$value = $matches[2][$index];
if(stripos($value, ',') !== FALSE) {
$value = explode(',',$value);
}
$new_desc[$identifier] = $value;
}
var_dump($new_desc);
The full working DEMO can be found here.
Use preg_match_all() to extract the key value pairs first:
preg_match_all('/[A-Z][a-z]+:[a-z\d, ]+/', $description, $matches);
Then loop through the $matches array and use explode() to create your result array:
foreach ($matches[0] as $value) {
list($key, $qty) = explode(':', $value);
if (strpos($qty, ',') !== FALSE) {
$result[strtolower($key)] = array_map('trim', explode(',', $qty));
} else {
$result[strtolower($key)] = trim($qty);
}
}
var_dump($result);
Output:
array(3) {
["title"]=>
string(5) "title"
["price"]=>
string(4) "1000"
["color"]=>
array(3) {
[0]=>
string(3) "red"
[1]=>
string(5) "green"
[2]=>
string(4) "blue"
}
}
Demo

Categories