我有多种语言字符串格式如下:
[en]这是英语[es] est esespañol[fr]C'estfrançaise[it]Questoèitaliano
语言的顺序并不总是相同,并非所有语言都可用。
我正在尝试提取特定的语言字符串,但没有成功。语言字符串包含HTML,以及任何类型的特殊字符,空格,换行符,制表符等。
假设我想提取英文部分;我需要一个正则表达式能够匹配[en]部分之后的所有内容(新行,回车符,特殊字符,制表符等),直到新语言字符串的开头:([a-z] {2})
这不起作用:还返回法语字符串,如果西班牙语字符串位于过去位置,则不返回任何内容。
/\[es\]((.|\n|\t|\r)*)(\[([a-z]{2})\])/u
我无法为以下内容编写正则表达式:“[es]之后的任何内容,不是括号内的两个字母或字符串的结尾”
非常感谢任何帮助!
答案 0 :(得分:5)
你真正的问题是贪婪匹配。有几种方法可以解决这个问题。懒惰匹配:
/\[es\]((?:.|\n|\t|\r)*?)\[([a-z]{2})\]/u
否定前瞻:
/\[es\]((?:(?!\[([a-z]{2})\])(?:.|\n|\t|\r))*)/u
你知道,Regex引擎是贪婪,这意味着它会捕获尽可能多的令牌并且回溯直到它有匹配的字符串 - 常见的说法是引擎返回可能的最大捕获量。您可以使用 lazy 匹配器(任何匹配器后跟?
- 所以??
,*?
,+?
等等,这会颠倒匹配行为和尽可能少的捕获,慢慢抓住更多,直到它匹配。您还可以使用前瞻来确保您匹配的通配符不包含您的分隔符字符串。
您还可以使用s
修饰符强制执行。匹配所有内容,包括换行符(它已匹配\t
字符。
/\[es\](.*?)\[([a-z]{2})\]/su
对这个故事要谨慎,如果Hercules打架,你就会失败!如果你的字符串里面有任何看起来像语言代码的东西,但不是 - 这个正则表达式会失败。
答案 1 :(得分:1)
FrankieTheKneeMan写了一个很好的解释贪婪和懒惰行为之间的区别。
要利用贪婪行为而不回溯(或回溯非常有限),您可以使用否定的字符类:
/\[es]([^[]*)/u
(请注意,您不需要s修饰符,因为您不使用点。)
如果:但是,先前的模式不允许在您要匹配的内容中使用左方括号。如果检查每个[
不是语言标记的开头,则可以解决此问题:
/\[es]((?>[^[]+|\[(?![a-z]{2}]))*)/u