2009-06-25 137 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字符串字面量:

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