2017-08-15 49 views
2

我存储在MySQL数据库中的以下提取键/值值。preg_match_all从模板

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

下面是代码:

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 
My name is ... 
I am from ... 

我tryed各种正则表达式,但我总是以相同的结果。

回答

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

详细

  • ^条目 - 的开头匹配line(由于m改性剂)
  • %(\w+)% - 匹配%,然后匹配并捕捉到第1组的一个或多个字字符,接着匹配%
  • (.*?) - 比赛和捕捉到2任0+字符组尽可能少,最多的第一次出现...
  • (?=^%\w+%|\z) - 一条线,%,1+字字符,%或字符串的末尾开始(\z可能与\Z代替在这里,因为刚刚结束串的位置就足够了)。

展开的版本:

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

another demo。该(.*(?:\R(?!%\w+%).*)*)部分以下为2小组赛:

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

谢谢你很多。我会尽快将您的答案标记为已接受。这解决了我的问题。 – user2933212

+0

这两种模式都是错误的。如果你有一个特殊字符的URL替换为十​​六进制表示,如:http://domain.tld/fo%20%20lder/index.php?path = http%3A%2F%2Fotherdomain.tld?而不是使用'%',你应该使用换行符。 –

+0

@CasimiretHippolyte:你不能说模式是错误的*,我建议基于原始模式的模式*不依赖于换行符。很容易在第一个正则表达式中添加锚点和MULTILINE修改器来修复它,然后它可以很容易地展开。 –

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,如果你真的想保持换行符,但..我只是认为你没有)