2017-08-15 46 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,如果你真的想保持換行符,但..我只是認爲你沒有)