如何使用PHP preg_match_all来获取自定义标记内的内容(不是html),

时间:2014-08-09 13:53:34

标签: php regex preg-match-all

我要为多语言网站保存用户名和bio。因为使用的语言数量会随着时间的推移而改变,所以我试图以下列格式从html textarea中获取它们。

[lang:en]
Some content some content some content
some content some content
some content 
[endlang:en]

[lang:zh]
有些内容有些内容有些内容
一些内容有些内容
一些内容
[endlang:zh]

因此,在提交表单时,我想获取根据语言分隔的内容。 我正在使用preg_match_all:

$count = preg_match_all('|\[lang:([a-z]{2})\](.*)\[endlang:[a-z]{2}\]|si',$value,$matches);

但它没有抓到任何东西。我该怎么做才能修复这个表达式?

2 个答案:

答案 0 :(得分:3)

你的正则表达目前是贪婪的; the dot.)尽可能匹配,因此它会匹配[lang:xx]代码和[endlang:xx]代码之间的所有内容。为了解决此问题,您可以通过在结尾处添加?来使模式变得懒惰,如下所示:

\[lang:([a-z]{2})\]\R*(.*?)\R*\[endlang:\1\]

请注意,我还在正则表达式中使用\R来捕获字符串中的任何垂直空白字符 - 这样,换行符不会包含在匹配结果中。

此外,开始标记中的语言代码可能与匹配的结束标记中使用的语言代码不同。我在结束标记中使用了backreference\1)来避免这种情况 - 它使匹配更加健壮。

完整代码:

$pattern = '|\[lang:([a-z]{2})\]\R*(.*?)\R*\[endlang:\1\]|si';

preg_match_all($pattern, $value, $matches);

// Combine the languages and matched strings to create an associative array
$result = array_combine($matches[1], $matches[2]);

var_dump($result);

Demo

答案 1 :(得分:1)

默认情况下,PHP正则表达式会表现得贪婪。因此,您的版本将匹配第一个开始标记和最后一个结束标记。您可以通过添加来指定非贪婪行为吗?到这样的相应部分:

$count = preg_match_all('|\[lang:([a-z]{2})\](.*?)\[endlang:[a-z]{2}\]|si',$value,$matches);

这将使表达式在标签之间选择尽可能少的行。我刚刚对它进行了测试,似乎有效。