Como analisar para string to multidimensional array (regex?)

Eu preciso passar os dados para uma matriz por blocos, como posso fazer isso? Preciso usar regex? Meu script me dá erros porque não consigo separá-lo como eu deseje. Alguém tem alguma idéia?

Dados:

~0 11111111 ~1 222222222 ~2 3333333333 ~end ~0 aaaaaaaaaaa ~1 bbbbbbbbbb ~2 cccccccccc ~3 ddddddddddd ~end ~0 yyyyyyyyyyy xxxxxxxx ffffffffff ~1 rrrrrrrrrrrr ~end 

Eu preciso disso assim:

 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 ) ), ) 

Meu código (falha):

 $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; } 

Aqui está uma maneira não-regex: dividir a string em linhas e iterar sobre elas. Verifique as condições que você especificou e adicione cada linha a uma sub-matriz se atender às condições. Então, quando você chegar a uma linha ~end , anexe a sub-matriz à matriz principal.

 $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 = []; } } 

Para uma solução regex, comece por explodir em ~end para quebrar o texto principal em seções, então preg_match_all nas seções para encontrar linhas que atendam às suas condições.

 foreach (explode('~end', $texto, -1) as $section) { preg_match_all('/\n *(?!~)(\w+)/', $section, $matches); if ($matches[1]) $result[] = $matches[1]; } 

(?!~) é um lookbehind negativo para excluir linhas que começam com ~ . Talvez haja alguma maneira de fazer tudo com uma grande regex legal, mas não sou tão bom nisso.

Porque você deseja que seus sub-blocos sejam separados em blocos na matriz de saída, é necessário que haja dois passos no método. A razão é que seus sub-blocos têm diferentes contagens de grupos de captura e a regex não permitirá essa variabilidade.

Código:

 // 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); 

Saída * reformatado / condensado para economizar espaço nesta página ( Ver demonstração ):

 array( array('11111111','222222222','3333333333'), array('aaaaaaaaaaa','bbbbbbbbbb','cccccccccc','ddddddddddd'), array('yyyyyyyyyyy xxxxxxxx ffffffffff','rrrrrrrrrrrr') ) 

Alternativamente, se você quiser ter todos os sub-blocos listados em uma matriz de 1-dim (não dividido por blocos), a matriz de saída pode ser construída em uma etapa:

 if(preg_match_all("/(?:\~\d+\s*)\K.+?(?:\s+\S+)*?(?=\s+\~)/s", $texto, $coincidencias)){ var_export($coincidencias[0]); } 

Saída 1-dim:

 array ( 0 => '11111111', 1 => '222222222', 2 => '3333333333', 3 => 'aaaaaaaaaaa', 4 => 'bbbbbbbbbb', 5 => 'cccccccccc', 6 => 'ddddddddddd', 7 => 'yyyyyyyyyyy xxxxxxxx ffffffffff', 8 => 'rrrrrrrrrrrr', )