2009-06-25 99 views
0

试图提取用双括号括起来的字符串。例如[[这是一个令牌]]应该匹配。为了使事情更优雅,应该有一个转义序列,这样像\ [[这个转义符\]]的双括号内容就不会匹配。Java中的RegEx无法正常工作

用“组1”提取标记的模式[^\\\\]([\\[]{2}.+[^\\\\][\\]]{2})接近,但有些情况下它不起作用。问题似乎是,第一个“不”的语句被评估为“除反斜线外的任何内容”。问题是,“任何事物”都不包括“无”。那么,什么使这种模式匹配“没有任何或任何字符比反斜杠”?

这里是一个单元测试来展示所需的行为:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import junit.framework.TestCase; 

public class RegexSpike extends TestCase { 
    private String regex; 
    private Pattern pattern; 
    private Matcher matcher; 

    @Override 
    protected void setUp() throws Exception { 
     super.setUp(); 
     regex = "[^\\\\]([\\[]{2}.+[^\\\\][\\]]{2})"; 
     pattern = Pattern.compile(regex); 
    } 

    private String runRegex(String testString) { 
     matcher = pattern.matcher(testString); 
     return matcher.find() ? matcher.group(1) : "NOT FOUND"; 
    } 

    public void testBeginsWithTag_Passes() { 
     assertEquals("[[should work]]", runRegex("[[should work]]")); 
    } 

    public void testBeginsWithSpaces_Passes() { 
     assertEquals("[[should work]]", runRegex(" [[should work]]")); 
    } 

    public void testBeginsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("anything here[[should 
work]]")); 
    } 

    public void testEndsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("[[should 
work]]with anything here")); 
    } 

    public void testBeginsAndEndsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("anything here[[should 
work]]and anything here")); 
    } 

    public void testFirstBracketsEscaped_Fails() { 
     assertEquals("NOT FOUND", runRegex("\\[[should NOT work]]")); 
    } 

    public void testSingleBrackets_Fails() { 
     assertEquals("NOT FOUND", runRegex("[should NOT work]")); 
    } 

    public void testSecondBracketsEscaped_Fails() { 
     assertEquals("NOT FOUND", runRegex("[[should NOT work\\]]")); 
    } 

} 
+0

什么也不做的意思是NULL或空白? – northpole 2009-06-25 16:59:20

回答

3

您可以简单地使用(^|[^\\]),这将要么匹配字符串的开头(只要你设置你的正则表达式的MULTILINE模式)单个字符不是一个反斜杠(包括空格,换行符等)。

您也想与.+?更换.+,否则一个字符串,如"[[one]] and [[two]]"将被视为一个单一的匹配项,其中"one]] and [[two"被认为是括号内。

第三点是您不必在[]的字符类中包装单个字符(即使是逃脱的字符,如\[\])。

这样就会使下面的正则表达式(原谅我去掉双escapedness为清楚起见):

(^|[^\\])(\[{2}.+?[^\\]\]{2}) 

(另请注意,你不能用你的正则表达式逃离转义字符两个斜杠前[将不会被解析为单个(转义)斜线,但会指示单个(未转义)斜线和转义括号。)

1

你想要一个“零宽度负回顾后发断言”,这是(?<!expr)。尝试:

(?<!\\\\)([\\[]{2}.+[^\\\\][\\]]{2}) 

实际上,这可以被简化,并且通过切割那些一些不必要括号中,并加入用于关闭托架负回顾后,也更普遍。 (如果你在字符串中间有一个转义括号,你的版本也会失败,如[[text\]]moretext]])。

(?<!\\\\)(\\[{2}.*?(?<!\\\\)\\]{2}) 
1

该字符串应该发生什么? (实际的字符串内容,不是Java文字。)

foo\\[[blah]]bar 

我在问的是您是否支持转义反斜杠。如果你是这样,后顾无效。你不必寻找一个单一的反斜杠,而是需要检查它们的奇数但未知数,Java向后看就不能像这样开放。另外,那么里面的转义括号怎么样 - 这个有效吗?

foo[[blah\]]]bar 

在任何情况下,我建议你在来从另一个方向反斜线问题:匹配任意数量转义字符(即反斜杠加任何东西)紧接在第一托架作为令牌的一部分前述的。在令牌内部,匹配除方括号或反斜线外的任意数量的字符,或任意数量的转义字符。下面是实际的正则表达式:

(?<!\\)(?:\\.)*+\[\[((?:[^\[\]\\]++|\\.)*+)\]\] 

...这里是作为一个Java字符串字面量:

"(?<!\\\\)(?:\\\\.)*+\\[\\[((?:[^\\[\\]\\\\]++|\\\\.)*+)\\]\\]"