【问题标题】:Regex to get string between curly bracket tags in PHP正则表达式在 PHP 中的大括号标签之间获取字符串
【发布时间】:2021-06-26 15:04:15
【问题描述】:

$HTML:

{list:start:Data}
   {id} is having a title of {title}
{list:end:Data}

数据是动态的,可以是任何字符串。

我正在尝试使用以下代码循环所有出现的事件:

preg_match_all('/\{list:start:(.*?)\}(.*?)\{list:end:(.*?)\}/', $HTML, $match);

我想要以下结果:

$match = array(
   array(
      "string" => "Data",
      "value" => "{id} is having a title of {title}"
   )
);

但我得到以下结果:

$match = array(
   [0] => Array
        (
        )

    [1] => Array
        (
        )

    [2] => Array
        (
        )

    [3] => Array
        (
        )
);

但这不起作用,因为 $match 返回一个空数组。在寻找解决方案几个小时后,我仍然没有接近工作结果。

【问题讨论】:

  • 您能否提供示例值以便您的问题有minimal, reproducible example?还请扩展“不工作” - 到底发生了什么?
  • @El_Vanja 请查看更新后的问题。谢谢
  • 我仍然不清楚这里发生了什么。 $HTML 应该是一个字符串,那么你怎么期望一个数组在里面呢?
  • $HTML 的 var_dump 能给你带来什么?
  • 如果你不想跨越以list:3v4l.org/shT5S开头的行

标签: php arrays regex


【解决方案1】:

作为替代方案,您可以使用negated character class 而不是使用带有/s 修饰符的.*? 来让点匹配换行符。

如果您不想匹配以{list: 开头的连续行,您可以使用否定前瞻来排除这些匹配。

^{list:start:([^}]+)}\R((?:(?!{list:).*\R)*+){list:end:[^}]+}

模式匹配:

  • ^ 字符串开始
  • {list:start: 字面匹配(注意{ 不需要转义)
  • ( 捕获第 1 组
    • [^}]+ 匹配除 } 之外的任何字符 1+ 次
  • )关闭第一组
  • } 匹配结束}
  • \R 匹配任何 unicode 换行符序列
  • ( 捕获第 2 组
    • (?:(?!{list:).*\R)*+ 重复匹配所有行,只要它们不以list: 开头
  • )关闭第二组
  • {list:end: 字面匹配
  • [^}]+ 匹配除 } 之外的任何字符 1+ 次
  • } 匹配结束}

查看regex demoPhp demo

示例代码

$re = '/^{list:start:([^}]+)}\R((?:(?!{list:).*\R)*){list:end:[^}]+}/m';
$str = '{list:start:Data}
   {id} is having a title of {title}
{list:end:Data}

{list:start:Data}
{list:start:Data}
   {id} is having a title of {title}
this is some text
{list:end:Data}';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

print_r(array_map(function($x){
    return [
        "string" => $x[1],
        "data" => trim($x[2])
    ];
}, $matches));

输出

Array
(
    [0] => Array
        (
            [string] => Data
            [data] => {id} is having a title of {title}
        )

    [1] => Array
        (
            [string] => Data
            [data] => {id} is having a title of {title}
this is some text
        )

)

【讨论】:

    【解决方案2】:

    您需要转义大括号,并使用/s 匹配多行。下面是代码示例。


    代码

    <?php
    
    $input = '
    {list:start:Data}
       {id} is having a title of {title}
    {list:end:Data}
    
    {list:start:Data1}
       {id1} is having a title of {title1}
    {list:end:Data1}
    
    {list:start:Data2}
       {id2} is having a title of {title2}
    {list:end:Data2}
    
    {list:start:Data3}
       {id3} is having a title of {title3}
    {list:end:Data3}
    
    ';
    
    preg_match_all(
        "/\\{list:start:(.+?)\\}(.*?)\\{list:end:(.+?)\\}/s",
        $input,
        $preg_matches
    );
    
    $matches = [];
    foreach ($preg_matches[1] as $k => $v) {
        $matches[] = [
            "string" => trim($v),
            "data" => trim($preg_matches[2][$k])
        ];
    }
    
    print_r($matches);
    

    输出

    Array
    (
        [0] => Array
            (
                [string] => Data
                [data] => {id} is having a title of {title}
            )
    
        [1] => Array
            (
                [string] => Data1
                [data] => {id1} is having a title of {title1}
            )
    
        [2] => Array
            (
                [string] => Data2
                [data] => {id2} is having a title of {title2}
            )
    
        [3] => Array
            (
                [string] => Data3
                [data] => {id3} is having a title of {title3}
            )
    
    )
    

    【讨论】:

    • 非常感谢!正是我正在寻找的答案。
    猜你喜欢
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2010-09-29
    • 2013-07-20
    相关资源
    最近更新 更多