preg_match_all - 从模板中提取键/值

时间:2017-08-15 17:48:58

标签: php regex preg-match-all

我将以下内容存储在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 ...

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

2 个答案:

答案 0 :(得分:2)

您可以使用

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

请参阅regex demo

<强>详情

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

相同的展开的表达式(效率更高)将看起来像

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

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

[^%]*(?:%(?!\w+%)[^%]*)*匹配除%以外的任何0 +字符,然后匹配0个或更多后续出现的%未跟随1个字字符,然后%其次是%以外的任何0 +字符。

如果您的参赛作品始终显示在不同行的开头,则可以使用

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

请参阅此regex demo

<强>详情

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

展开版:

\Z

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

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

答案 1 :(得分:1)

一种无正则表达式的方法:

$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。我只是假设您没有这样做

相关问题