正则表达式中的非获取匹配
正则表达式是代码中的常用技巧,主要用来匹配符合某种句法规则的字符串。常用的正则表达式本文不再赘述,详细可以参考wiki(Python,Java)。本文主要讨论的是非获取匹配的正则表达式。
常见的非获取匹配有以下几种:
(?:pattern) 主要用来匹配pattern但不获取结果。我们看下面的例子。
>>> re.match("win (7|vista)", "win 7").group() 'win 7' >>> re.match("win (7|vista)", "win 7").groups() ('7',) >>> re.match("win (?:7|vista)", "win 7").group() 'win 7' >>> re.match("win (?:7|vista)", "win 7").groups() ()
可以看出,使用这种模式括号中匹配内容并没有存储供以后使用。它是比“win 7|win vista”更加简便的形式。
以上是Python的示例,Java代码如下(以后的例子不再赘述):
Pattern ptn = Pattern.compile("win (7|vista)"); Matcher m = ptn.matcher("win 7"); while (m.find()) { for (int i = 0; i <= m.groupCount(); i++) { System.out.println(m.group(i)); } }
(?=pattern) 正向肯定预查。它在任何匹配pattern的字符串处查找字符串,它仅仅是检查是否匹配,而不将预查的结果包含其中。当然,它也是非获取匹配。看个例子就明白了。
>>> re.match("win (?=7|vista)", "win 7").group() 'win ' >>> re.match("win (?=7|vista)", "win 7").groups() ()
(?!pattern) 正向否定预查。例子如下:
>>> re.match("win (?!7|vista)", "win 8").group() 'win ' >>> re.match("win (?!7|vista)", "win 8").groups() ()
(?<=pattern) 反向肯定预查。查找某个字串之前是否满足pattern。
>>> re.search("(?<=95|98)win", "98win").group() 'win' >>> re.search("(?<=95|98)win", "98win").groups() ()
(?<!pattern) 反向否定预查。
>>> re.search("(?<!95|98)win", "7win").group() 'win' >>> re.search("(?<!95|98)win", "7win").groups() ()
现在我们来看实际中的需求。现在我有一个字符串,这个字符串是由中文和英文组成,现在我要把这个字符串切成一个个只由中文或者英文组成的字串。比如说将“McCulloch与Pitts将神经系统”切成”McCulloch“、“与”、“ Pitts“、”将神经系统“。
首先要知道匹配中文的正则是”[\u4e00-\u9fa5]“,在Python中,我们可以使用findall方法:
reg = re.compile(u"[\u4e00-\u9fa5]+|[A-Za-z]+") print "\t".join([w for w in reg.findall(u"McCulloch与Pitts将神经系统")])
对于Java,除了使用这种方式匹配,我们还使用刚刚说过的非获取匹配来达到同样的效果。对于需求的句子,可以看到要切分的地方,要么是中文接英文,要么是英文接中文。所以我们在反向肯定预查到中文然后正向肯定预查到英文处调用split操作,或者在反向肯定预查到英文正向肯定预查到中文处调用同样的操作。于是有:
Pattern ptn = Pattern.compile( "(?<=[\u4e00-\u9fa5])(?=[A-Za-z])|(?<=[A-Za-z])(?=[\u4e00-\u9fa5])", Pattern.UNICODE_CASE); String[] words = ptn.split("McCulloch与Pitts将神经系统"); for(String word: words) { System.out.print(word + "\t"); }
可以看到达到了一样的效果,但是,在我的测试中,此法对Python中的正则库中的split方法并不适用。所以我们解决问题确实需要灵活多变的策略。
最后,我们再讨论以下js的实现。对于js来说,由于js不支持反向预查。所以,用和Python方法类似的简单策略。我们使用加上“g“修饰符的match方法(表示全局匹配,而不是只匹配一次)。
var testStr = "McCulloch与Pitts将神经系统"; var regExp = /[\u4e00-\u9fa5]+|[A-Za-z]+/g; testStr.match(regExp).forEach(function(i){ document.write(i+" "); });