问题
I need to pass the data to an array by blocks, how can I make this? Do I need to use regex? My script gives me errors because I can not separate it as I wish. Does anyone have any ideas?
Data:
~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end
I need it like this:
Array (
[0] => Array
(
[0] => 11111111
[1] => 222222222
[2] => 3333333333
)
),
[1] => Array
(
[0] => aaaaaaaaaaa
[1] => bbbbbbbbbb
[2] => cccccccccc
[3] => ddddddddddd
)
),
[2] => Array
(
[0] => yyyyyyyyyyy
xxxxxxxx
ffffffffff
[1] => rrrrrrrrrrrr
)
),
)
My code (Fail):
$texto = "~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end";
preg_match_all("/(?ms)^~0.*?~end/", $texto, $coincidencias);
foreach ( $coincidencias[0] as $bloque ){
preg_match_all("/\~.*\n/", $bloque, $sub_bloques);
$hola[] = $sub_bloques;
}
回答1:
Here is one non-regex way: split the string into lines and iterate over them. Check for the conditions you've specified and add each line to a sub-array if it meets the conditions. Then when you get to an ~end
line, append the sub-array to the main array.
$sub_bloques = [];
$hola = [];
foreach(array_map('trim', explode("\n", $texto)) as $line) {
if ($line && substr($line, 0, 1) !== '~') {
$sub_bloques[] = $line;
}
if ($line == '~end') {
$hola[] = $sub_bloques;
$sub_bloques = [];
}
}
For a regex solution, start by exploding on ~end
to break the main text into sections, then preg_match_all
on the sections to find lines that meet your conditions.
foreach (explode('~end', $texto, -1) as $section) {
preg_match_all('/\n *(?!~)(\w+)/', $section, $matches);
if ($matches[1]) $result[] = $matches[1];
}
(?!~)
is a a negative lookbehind to exclude lines that start with ~
. Maybe there's some way to do the whole thing with one big cool regex, but I'm not that good at it.
回答2:
Because you want to have your sub-blocks separated into blocks in your output array, there needs to be two-steps in the method. The reason is that your sub-blocks have differing capture group counts and regex will not permit this variability.
Code:
// This delivers the sub-blocks in their relative blocks as requested in the OP
foreach (preg_split('/\s+~end\s*/',$texto) as $bloque) {
if(preg_match_all('/(?:\~\d+\s+)\K.+?(?:\s+\S+)*?(?=\s+\~|$)/',$bloque,$sub_bloques)){
$hola[]=$sub_bloques[0];
}
}
var_export($hola);
Output *reformatted/condensed to save space on this page (View Demo):
array(
array('11111111','222222222','3333333333'),
array('aaaaaaaaaaa','bbbbbbbbbb','cccccccccc','ddddddddddd'),
array('yyyyyyyyyyy
xxxxxxxx
ffffffffff','rrrrrrrrrrrr')
)
Alternatively, if you want to have all sub-blocks listed in a 1-dim array (not divided by blocks) the output array can be built in one step:
if(preg_match_all("/(?:\~\d+\s*)\K.+?(?:\s+\S+)*?(?=\s+\~)/s", $texto, $coincidencias)){
var_export($coincidencias[0]);
}
1-dim output:
array (
0 => '11111111',
1 => '222222222',
2 => '3333333333',
3 => 'aaaaaaaaaaa',
4 => 'bbbbbbbbbb',
5 => 'cccccccccc',
6 => 'ddddddddddd',
7 => 'yyyyyyyyyyy
xxxxxxxx
ffffffffff',
8 => 'rrrrrrrrrrrr',
)
来源:https://stackoverflow.com/questions/41266309/how-to-parse-to-string-to-multidimensional-array-regex