【问题标题】:preg_match_all - Extract key / value from templatepreg_match_all - 从模板中提取键/值
【发布时间】:2017-08-15 17:48:58
【问题描述】:

我将以下内容存储在 mysql 数据库中:

%URL% https://google.com
%TEXT% Hello world!
%LARGETEXT% Hello
My name is ...
I am from ...

我的目标是将包含在 % 中的字符串转换为 PHP 数组键,除此之外的字符串就是值。

问题是,我的正则表达式没有提取多行字符串。

代码如下:

preg_match_all ("/%(\w+)%(.*)/", $msg, $matches);

它确实输出:

  [1]=>
  array(3) {
    [0]=>
    string(5) "BASIC"
    [1]=>
    string(4) "TEXT"
    [2]=>
    string(9) "LARGETEXT"
  }
  [2]=>
  array(3) {
    [0]=>
    string(18) " https://google.de"
    [1]=>
    string(13) " Hello world!"
    [2]=>
    string(6) " Hello"
  }

在第二个数组中只显示“Hello”,而不是:

Hello
My name is ...   
I am from ...

我尝试了各种正则表达式,但我总是得到相同的结果。

【问题讨论】:

    标签: php regex preg-match-all


    【解决方案1】:

    你可以使用

    ~%(\w+)%(.*?)(?=%\w+%|$)~s
    

    regex demo

    详情

    • % - 一个百分号
    • (\w+) - 第 1 组:一个或多个单词字符
    • % - 百分号
    • (.*?) - 第 2 组:任何 0+ 个字符(请注意,s 修饰符也会让 . 匹配换行符)尽可能少,直到第一次出现...
    • (?=%\w+%|$) - %,1+ 字字符,% 或字符串结尾。

    一个相同的展开表达式(更有效的)看起来像

    ~%(\w+)%([^%]*(?:%(?!\w+%)[^%]*)*)~
    

    (不需要s 修饰符)。请参阅regex demo

    [^%]*(?:%(?!\w+%)[^%]*)* 匹配除 % 之外的任何 0+ 个字符,然后匹配 0 次或多次后续出现的 % 后不带 1+ 个单词字符,然后匹配 % 后跟除%.

    如果您的条目总是出现在不同行的开头,您可以使用

    ~^%(\w+)%(.*?)(?=^%\w+%|\z)~sm
    

    看到这个regex demo

    详情

    • ^ - 匹配的开始(由于m修饰符)
    • %(\w+)% - 匹配%,然后匹配并捕获到第1组一个或多个单词字符,然后匹配%
    • (.*?) - 将任何 0+ 个字符尽可能少地匹配并捕获到第 2 组中,直到第一次出现...
    • (?=^%\w+%|\z) - 一行的开头,%,1+ 字字符,% 或字符串的最后(\z 可以在这里替换为\Z,因为字符串位置的结尾就足够了)。

    展开版:

    ~^%(\w+)%(.*(?:\R(?!%\w+%).*)*)~m
    

    another demo(.*(?:\R(?!%\w+%).*)*) 部分将以下内容匹配到第 2 组:

    • .* - % 之后的行的其余部分,1+ 字字符,% 子字符串
    • (?:\R(?!%\w+%).*)* - 匹配 0+ 个连续出现的:
      • \R(?!%\w+%) - 一个换行序列 (\R),它后面没有 %、1+ 个单词字符和 %,然后...
      • .* - 除换行符之外的任何 0+ 个字符,尽可能多,直到行尾。

    【讨论】:

    • 非常感谢。我会尽快将您的答案标记为已接受。这解决了我的问题。
    • 这两种模式是错误的。如果您的 URL 中的特殊字符被替换为十六进制表示形式,例如:http://domain.tld/fo%20%20lder/index.php?path=http%3A%2F%2Fotherdomain.tld,该怎么办?而不是使用%,您应该使用换行符。
    • @CasimiretHippolyte:你不能说模式是错误的,我建议的模式是基于没有依赖的原始模式换行符。很容易在第一个正则表达式中添加锚点和 MULTILINE 修饰符来修复它,然后就可以轻松展开。
    • @CasimiretHippolyte 按照 OP 的规范,我认为,这里的字符串 20 实际上是包裹在 %% 中,因此是一个键。此规则没有例外。
    【解决方案2】:

    无正则表达式的方法:

    $str=explode('%',$str);
    $arr=[];
    for($i=1;$i<count($str);$i+=2){
        $arr[$str[$i]]=trim($str[$i+1]);
    }
    var_dump($arr);
    

    seems to work fine.(如果你真的想保留换行符,请删除trim。我只是假设你没有)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2020-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多