如何使用正则表达式表示「非」逻辑?
'^'
可以表示排除的逻辑:
[^abc] # 除abc之外的所有字符
然而这个简单的表示符号并不总是有效果的。考虑这样的需求:匹配后缀名不为 '.jpg'
的字符串。使用 '^'
是无法满足需求的。
正则表达式还有一个非常有用的功能——环视(lookaroud)。
环视包括顺序环视(lookahead)和逆序环视(lookbehind);每种又分为肯定和否定两种。利用环视可以为我们本想匹配的部分设置一个特定的「环境」。
(?=...) positive lookahead: Matches if ... matches next, but doesn't consume the string.
(?!...) negative lookahead: Matches if ... doesn't match next.
(?<=...) posttive lookbehind: Matches if preceded by ... (must be fixed length).
(?<!...) negative lookbehind: Matches if not preceded by ... (must be fixed length).
环视类似于一条断言,从当前位置的字符开始匹配环视表达式,如果匹配成功,则会从环视表达式匹配到的开始位置继续匹配后续的正则表达式,否则本次匹配失败。
例子🌰:
pattern = '^((?!\.jpg$).)+$'
表示不以 '.jpg'
结尾的所有字符串。
在这个例子中,^.+$
是我们真正想匹配的模式,当加上前面的环视表达式 (?!\.jpg$)
的时候,会在每次匹配开始之前,先先匹配环视表达式里指定的模式,因为我们用的是「顺序否定」的环视表达式,所以会从当前位置向后匹配,期待环视表达式匹配失败。这里的这条环视表达式的意思是「从当前位置开始,不能以 .jpg 作为结束」。
例子🌰:
pattern = '(?<![\d,])(\d{1,3}(,\d{3})*)(?![\d,])
表示从右往左每三位数字由一个逗号隔开的数字。
用上面的例子,可以从一段字符串中,匹配到符合上述要求的格式的数字。主要使用了2个环视表达式去限定数字模式所处的「环境」。(?![\d,])
是一个顺序的否定环视,他表示从当前位置开始,向右匹配数字或者逗号,并且期待匹配失败。如此限定了,已匹配的数字模式右边不能有数字或者逗号。?<![\d,]
同样,不过他是从当前位置开始,从右往左匹配,同样限制了已匹配的数字模式左边不能有数字或者逗号。
除以上2个简单的例子,环视表达式还有其他有用的途径。
理解的关键在于:环视表达式是一个预匹配,它不会占用匹配位置;它是从指定了环视表达式的位置开始匹配,可以向左也可以向右;它的期待结果可以是成功,也可以是失败。
关键的一个用途是,限定想匹配的模式的「环境」。
参考
网友评论