【问题标题】:How to parse to string to multidimensional array (regex?)如何将字符串解析为多维数组(正则表达式?)
【发布时间】:2023-03-04 20:31:01
【问题描述】:

我需要将数据按块传递给数组,我该怎么做?我需要使用正则表达式吗?我的脚本给了我错误,因为我无法按照我的意愿将它分开。有人有什么想法吗?

数据:

~0 
11111111
~1 
222222222
~2 
3333333333

        ~end 
~0 
aaaaaaaaaaa
~1 
bbbbbbbbbb
~2 
cccccccccc
~3 
ddddddddddd 

        ~end 



~0 
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1 
rrrrrrrrrrrr
        ~end 

我需要这样的:

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 

                  )

          ),



)

我的代码(失败):

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

【问题讨论】:

  • 我不确定我是否正确理解了这些要求,您能确认一下吗? "每个非空行不以字符 ~ 开头,应该是数组中的一个条目"
  • @Dragos 从 "~0" 到 "~end" 是一个块(现在是 3 个块),每个块的文本在 ~0、~1、~2 到数组位置(只有文本)
  • 我宁愿分两步工作:1.$level1 = explode('~end', $data) 2.foreach ($level1 as $subItem) { $matches = preg_match_all('^(\w*)$', $subItem) }
  • @Dragos print_r($matches) => 0

标签: php arrays regex multidimensional-array preg-match-all


【解决方案1】:

这是一种非正则表达式的方式:将字符串拆分为行并对其进行迭代。检查您指定的条件,如果满足条件,则将每一行添加到子数组中。然后,当您到达~end 行时,将子数组附加到主数组。

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

对于正则表达式解决方案,首先在 ~end 上展开以将主要文本分成​​多个部分,然后在这些部分上 preg_match_all 以查找符合您条件的行。

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

(?!~) 是排除以~ 开头的行的否定回溯。也许有一些方法可以用一个很酷的正则表达式来完成整个事情,但我不太擅长。

【讨论】:

  • 这很棒,但是 (~0 yyyyyyyyyyy xxxxxxxx ffffffffff ) 是一个文本,而不是换行,文本有更多 \n ....
  • 对不起,我不确定我理解你的意思。你介意再向我解释一下吗?
  • 最后一个区块~0 yyyyyyyyyyy xxxxxxxx ffffffffff ,只有1个文本,不是3个位置
  • @dont-panic [2] => 数组([0] => yyyyyyyyyyy xxxxxxxx ffffffffff [1] => rrrrrrrrrrrr)
  • 嗯,好的。我以为这就是你的意思,但那不是我得到的。 3v4l.org/ro6Kb
【解决方案2】:

因为您希望将子块分成输出数组中的块,所以该方法需要有两个步骤。原因是您的子块具有不同的捕获组计数,而正则表达式不允许这种可变性。

代码:

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

输出 * 重新格式化/压缩以节省此页面上的空间 (View Demo):

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

或者,如果您希望将所有子块列在一个 1-dim 数组中(不按块划分),则可以一步构建输出数组:

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

1-dim 输出:

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

【讨论】:

  • @VictorMoscosoLembcke 如果我的回答满意,请给它打上绿色的勾(并可能因为有帮助而投票)。如果有些地方不太对劲,请在评论中向我解释,我会尽力修复它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 2023-03-06
相关资源
最近更新 更多