how can match some string from content in array (Right to Left)? - php

I have music chord and lyrics like this :
<p>[Fm]   [Gm]    [Dm]</p>
<p>لورم ایپسوم ، لورم ایپسوم</p>
<p>[A] [Asus4] [Bb]</p>
<p>لورم ایپسوم ، لورم ایپسوم</p>
the "p" tags generated by wordpress editor for each line.
I collect the Chord with brackets by using :
preg_match_all("/\[[^\]]*\]/", $content , $matches);
And result is :
[0] => [Fm]
[1] => [Gm]
[2] => [Dm]
[3] => [A]
[4] => [Asus4]
[5] => [Bb]
but I need to collect the chords from right to left and my array should be like this one :
[0] => [Dm]
[1] => [Gm]
[2] => [Fm]
[3] => [Bb]
[4] => [Asus4]
[5] => [A]
Thanks.

You could try to capture a single line first by matching to: (\[[^\]]*\])+(\<\\p\>){1}
You can then take a matched string and match it against your expression: /\[[^\]]*\]/.
If you take these secondary matches and put them in a 2d array you'll now have a object with this structure:
[0] => [Fm, Gm, Dm]
[1] => [A, Asus4, Bd]
Some (pseudo)code:
$outputarr = [];
preg_match_all("/(\[[^\]]*\])+(\<\\p\>){1}/", $content , $matches);
foreach ($matches as &$value) {
$internalarray = [];
preg_match_all("//\[[^\]]*\]/", $value , $matches2);
foreach ($matches2 as &$value2) {
array_push($internalarray, $value2);
}
array_push($outputarr, $internalarray);
}
You can now call the array_reverse function on elements [0] and [1] to get:
[0] => [Dm, Gm, Fm]
[1] => [Bd, Asus4, A]
And you can finally go from that to a single array by doing this:
$arr = [];
foreach ($outputarr as &$value) {
$arr = array_merge($arr, $value);
}
This should give your wanted inside variable $arr:
[0] => [Dm]
[1] => [Gm]
[2] => [Fm]
[3] => [Bb]
[4] => [Asus4]
[5] => [A]
ps: I haven't taken the whitespace characters into account and ((\[[^\]]*\])|\s)+(\<\\p\>){1} could be the better one. Furthermore this code could be improved by using array_merge and as such bypassing manual array_push

$content = "<p>[Fm] [Gm] [Dm]</p>
<p>لورم ایپسوم ، لورم ایپسوم</p>
<p>[A] [Asus4] [Bb]</p>
<p>لورم ایپسوم ، لورم ایپسوم</p>";
preg_match_all("/<p>.*<\/p>/", $content , $nodes);
$final = [];
foreach ($nodes[0] as $node ) {
if(!empty($node)) {
preg_match_all("/\[[^\]]*\]/", $node , $matches);
if(!empty($matches[0])) {
$final = array_merge($final, array_reverse($matches[0]));
}
}
}
print_r($final);

Related

PHP Explode string between two characters to arrays? (Noob question)

Hello :) I am a beginner in PHP.
I tried several times but did not succeed
I would like to parse a String like :
[1,[01,11,12],[20,21,22]]
to
`
arr[0][0]=>1
arr[1][0]=>01
arr[1][1]=>11
arr[1][2]=>12
arr[2][0]=>20
arr[2][1]=>21
arr[2][2]=>22
`
You can split your string on a comma that is not enclosed by [ and ] using this regex (inspired by this answer) with preg_split:
,(?![^\[]*\])
and then trim surrounding [ and ] from the resultant parts and split those strings on commas into succeeding elements of the output array. For example:
$string = '[1,[01,11,12] ,4 ,5, [20,21,22]]';
$parts = preg_split('/,(?![^\[]*\])/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
$output = array();
foreach ($parts as $part) {
$part = trim($part, '[] ');
$output[] = explode(',', $part);
}
print_r($output);
Output:
Array
(
[0] => Array
(
[0] => 1
)
[1] => Array
(
[0] => 01
[1] => 11
[2] => 12
)
[2] => Array
(
[0] => 4
)
[3] => Array
(
[0] => 5
)
[4] => Array
(
[0] => 20
[1] => 21
[2] => 22
)
)
Demo on 3v4l.org
If you're 100% certain of the source and safety of the string, you can also just use eval:
eval("\$output = $string;");
The result will be the same.

convert a string to multi dimensional array in php

I'm having trouble converting a string to a multi-dimensional array in php. This is my string:
$String = a,b,c|d,e,f|g,h,y|
This is what I'm trying:
$one=explode("|",$String);
foreach ($one as $item)
{
$one=explode(",",$one);
}
I'd like to create this array:
$array={ {a,b,c}, {d,e,f}, {g,h,y} };
Try with -
$one=explode("|",$String);
$array = array();
foreach ($one as $item){
$array[] = explode(",",$item);
}
Try this code:
$string = 'a,b,c|d,e,f|g,h,y|';
$arr = array_map(function($iter){ return explode(',',$iter);},explode('|',$string));
Hope it help a bit.
You have almost done it right, except for the cycle part. Try this
$result = [];
$String = 'a,b,c|d,e,f|g,h,y|';
$firstDimension = explode('|', $String); // Divide by | symbol
foreach($firstDimension as $temp) {
// Take each result of division and explode it by , symbol and save to result
$result[] = explode(',', $temp);
}
print_r($result);
Try this-
$String = 'a,b,c|d,e,f|g,h,y|';
$one = array_filter(explode("|", $String));
print_r($one); //Array ( [0] => a,b,c [1] => d,e,f [2] => g,h,y )
$result = array_map('v', $one);
function v($one) {
return explode(',',$one);
}
print_r($result); // Array ( [0] => Array ( [0] => a [1] => b [2] => c ) [1] => Array ( [0] => d [1] => e [2] => f ) [2] => Array ( [0] => g [1] => h [2] => y ) )
Use this code
$String= 'a,b,c|d,e,f|g,h,y|';
$one=explode("|",$String);
print_r(array_filter($one));
Output will be
Array
(
[0] => a,b,c
[1] => d,e,f
[2] => g,h,y
)

PHP: Parsing data within multidimensional array

I have an array which looks like this:
Array
(
[0] => Array
(
[0] => TE=140414100000 cd =AB1234 ggg =1234567 gbh =2
[7] => nd: DA1AAAAAAAAAA: TD = 140414:
)
[1] => Array
(
[0] => TE=140414100000 cd =AB1234 ggg =1234567 ghb =2
[7] => nd: DA1AAAAAAAAAA: TD = 140414:
)
)
what I am trying to acomplish is to parse data within each sub array and create a new multidimensional array with the parsed data.
Example: the data in parentheses below is what should be returned in new multidimensional array
Array
(
[0] => Array
(
[0] => te=(140414100000) cd =AB(1234) ggg =1234567 ghb =2
[7] => nd: DA(1)(AAAAAAAAAA): TD = (140414):
)
[1] => Array
(
[0] => te=(140414100000) cd =AB(1234) ggg =1234567 ghb =2
[7] => nd: DA(2)(BBBBBBBBBB): TD = (140414):
)
)
What I want to return:
Array
(
[0] => Array
(
[0] => 140414100000
[1] => 1234
[2] => 1
[3] => AAAAAAAAAA
[4] => 140414
)
[1] => Array
(
[0] => 140414100000
[1] => 1234
[2] => 2
[3] => BBBBBBBBBB
[4] => 140414
)
).
So my question is what would be the best way to acomplish this?
This is what I have come up with. It works, however is seems very inefficient as it adds a lot of empty arrays which have to be cleaned up.
foreach($new as $key => $val){
foreach($val as $res){
preg_match_all('%te=([0-9]{12})\s%',$res,$matches);
$out[$key][] = $matches[1][0];
preg_match_all('%cd\s+=AB([0-9]{4})%',$res,$matches);
$out[$key][] = $matches[1][0];
preg_match_all('%nd:\sDA([0-9]{1})%',$res,$matches);
$out[$key]['node'] = $matches[1][0];
preg_match_all('%nd:\sDA[0-9]{1}([a-zA-Z]{10,14}):%',$res,$matches);
$out[$key]['rset'] = $matches[1][0];
preg_match_all('%td\s=\s([0-9]{6}):%',$res,$matches);
$out[$key]['trdt'] = $matches[1][0];
}
}
foreach($out as $v){
$v = array_values(array_filter($v));
$return[] = $v;
}
return $return;
Thanks in advance.
UPDATED:
This worked and is much more efficient. Thanks for the example Shankar
foreach($new as $key => $val){
$v = implode('', $val);
preg_match_all("%te=([0-9]{12})|cd\s+=AB([0-9]{4})|nd:\sDA([0-9]{1})|([A-Z]{3,7}):|td=\s([0-9]{6}):%",$v,$matches);
$new_array[$key]['time'] = $matches[1][0];
$new_array[$key]['code'] = $matches[2][1];
$new_array[$key]['sp'] = $matches[3][2];
$new_array[$key]['rset'] = $matches[4][3];
$new_array[$key]['trfdt'] = $matches[5][4];
}
echo "<pre>";
print_r($new_array);
echo "</pre>";
Loop through your array and implode each array element and use a preg_match_all() to capture all the entries bewteen ( and ) and then pass those matches to your new array.
foreach($arr as $k=>$arr1)
{
$v = implode('',$arr1);
preg_match_all('^\((.*?)\)^', $v, $matches);
$new_arr[]=$matches[1];
}
print_r($new_arr);
Working Demo

Preg_match_all repeated group

this is my string:
zzzzzzz-------eh="koko"------eh="zizi"--------eh="mimi"--------xxxxxx
i need a reg-expression to extract koko, zizi and mimi
but eh='zizi' is optional:
so if it doesn't exist like in :
zzzzzzz----------eh="koko"-----------------eh="mimi"----------xxxxxx
i should get only koko and mimi.
the '---' are some text.
i tried
preg_match_all('#zzzzzzz(.*eh="([^"]*)"){2,3}.*xxxxxx#Uix', $strg , $out, PREG_SET_ORDER);
but it doesn't work.
note: the whole thing is like :
zzzzzzz--...--xxxxxxzzzzzzz--...--xxxxxxzzzzzzz--...--xxxxxxzz...
i need them grouped
like :
array():{
[0]:array():{
[0]:"zizi",
[1]:"mimi",
[2]:"koko",
},
[1]:array():{
[0]:"zizi",
[1]:"koko",
},
[2]:array():{
[0]:"zizi",
[1]:"fofo",
[2]:"bingo",
},
}
Why not just:
preg_match_all('/(?<=eh=")([^"]+)(?=")/', $strg, $out, PREG_SET_ORDER);
Regex101 Demo
This can be solved by capturing all strings preceded by =" until a " is found:
$s='zzzzzzz-------eh="koko"------eh="zizi"--------eh="mimi"--------xxxxxx';
if (preg_match_all('~(?<==")[^"]*~', $s, $arr))
print_r($arr);
OUTPUT:
Array
(
[0] => Array
(
[0] => koko
[1] => zizi
[2] => mimi
)
)
How about:
$str = 'zzzzzzz-------eh="koko"------eh="zizi"--------eh="mimi"--------xxxxxxzzzzzzz----------eh="koko"-----------------eh="mimi"----------xxxxxx';
$arr = preg_split('/(?<=x)(?=z)/', $str);
foreach($arr as $s) {
preg_match_all('/"([^"]+)"/', $s, $out);
$arr_out[] = $out[1];
}
print_r($arr_out);
output:
Array
(
[0] => Array
(
[0] => koko
[1] => zizi
[2] => mimi
)
[1] => Array
(
[0] => koko
[1] => mimi
)
)

PHP Group array by values

I have an array like this:
Array (
[0] => ing_1_ing
[1] => ing_1_amount
[2] => ing_1_det
[3] => ing_1_meas
[4] => ing_2_ing
[5] => ing_2_amount
[6] => ing_2_det
[7] => ing_2_meas
)
And I want to group the values into an array like this:
Array (
[0] => Array(
[0] => ing_1_ing
[1] => ing_1_amount
[2] => ing_1_det
[3] => ing_1_meas
)
[1] => Array(
[0] => ing_2_ing
[1] => ing_2_amount
[2] => ing_2_det
[3] => ing_2_meas
)
)
There may be many other items named like that: ing_NUMBER_type
How do I group the first array to the way I want it? I tried this, but for some reason, strpos() sometimes fails:
$i = 1;
foreach ($firstArray as $t) {
if (strpos($t, (string)$i)) {
$secondArray[--$i][] = $t;
} else {
$i++;
}
}
What is wrong? Can you advice?
It depends what you are trying to achieve, if you want to split array by chunks use array_chunk method and if you are trying to create multidimensional array based on number you can use sscanf method in your loop to parse values:
$result = array();
foreach ($firstArray as $value)
{
$n = sscanf($value, 'ing_%d_%s', $id, $string);
if ($n > 1)
{
$result[$id][] = $value;
}
}
<?php
$ary1 = array("ing_1_ing","ing_1_amount","ing_1_det","ing_1_meas","ing_2_ing","ing_2_amount","ing_2_det","ing_2_meas");
foreach($ary1 as $val)
{
$parts = explode("_",$val);
$ary2[$parts[1]][]=$val;
}
?>
This creates:
Array
(
[1] => Array
(
[0] => ing_1_ing
[1] => ing_1_amount
[2] => ing_1_det
[3] => ing_1_meas
)
[2] => Array
(
[0] => ing_2_ing
[1] => ing_2_amount
[2] => ing_2_det
[3] => ing_2_meas
)
)
What I'd do is something like this:
$result = array();
foreach ($firstArray as $value)
{
preg_match('/^ing_(\d+)_/', $value, $matches);
$number = $matches[1];
if (!array_key_exists($number, $result))
$result[$number] = array();
$result[$number][] = $value;
}
Basically you iterate through your first array, see what number is there, and put it in the right location in your final array.
EDIT. If you know you'll always have the numbers start from 1, you can replace $number = $matches[1]; for $number = $matches[1] - 1;, this way you'll get exactly the same result you posted as your example.

Categories