2012-03-15 43 views
7

我想構建一個正則表達式,它匹配'",然後匹配其他字符,當分別匹配'"時結束,具體取決於在右邊遇到的情況開始。所以這個問題看起來簡單得足以在最後使用反向引用來解決;這裏是下面一些正則表達式的代碼(這是在Java中那麼介意額外逃逸字符,如\"前):正則表達式;反向引用在字符集中不匹配的字符

private static String seekerTwo = "(['\"])([a-zA-Z])([a-zA-Z0-9():;/`\\=\\.\\,\\- ]+)(\\1)"; 

此代碼將成功地處理事情,如:

"hello my name is bob" 
'i live in bethnal green' 

的麻煩的是當我有一個這樣的字符串:

"hello this seat 'may be taken' already" 

使用上述正則表達式就可以將初始部分在遇到失敗'然後它會繼續併成功匹配'may be taken' ...但這顯然是不夠的,我需要整個字符串進行匹配。

我在想什麼,是我需要一種方法來忽略第一組中不匹配的引號類型,方法是將其作爲第三組字符集中的一個字符。但是,我知道沒有辦法做到這一點。有沒有某種鬼鬼祟祟的非反向引用功能或某種東西?我可以用來引用第一組中不匹配的字符?或者以其他方式解決我的困境?

+0

嗨,歡迎來到StackOverflow。我冒昧地重新格式化您的文章一點。你可以點擊編輯鏈接查看我是如何做到這一點的。非常重要的是要知道你是否需要發佈代碼... – 2012-03-15 11:15:14

回答

12

這可以使用負數lookahead assertions來完成。下面的解決方案,甚至考慮到了,你能逃脫在字符串中報價:

(["'])(?:\\.|(?!\1).)*\1 

說明:

(["']) # Match and remember a quote. 
(?:  # Either match... 
\\.  # an escaped character 
|   # or 
(?!\1) # (unless that character is identical to the quote character in \1) 
.  # any character 
)*  # any number of times. 
\1  # Match the corresponding quote. 

這正確匹配"hello this seat 'may be taken' already""hello this seat \"may be taken\" already"

在Java中,所有的反斜線:

Pattern regex = Pattern.compile(
    "([\"']) # Match and remember a quote.\n" + 
    "(?:  # Either match...\n" + 
    " \\\\. # an escaped character\n" + 
    "|   # or\n" + 
    " (?!\\1) # (unless that character is identical to the matched quote char)\n" + 
    " .  # any character\n" + 
    ")*  # any number of times.\n" + 
    "\\1  # Match the corresponding quote", 
    Pattern.COMMENTS); 
+0

+1爲一個深思熟慮和解釋的解決方案! – FloppyDisk 2012-03-15 11:22:16

+0

傑出的工作Tim,感謝您編輯我的文章。感謝你的建議,通過一些工作,我修改了我的代碼:「(['\」])([a-zA-Z])((?!\\ 1)[a-zA-Z0-9 ():; /''\「\\ = \\。\\,\\ - ])+(\\ 1)」這樣你的解決方案實際上已經夠簡單和完美的了。如果在主要字符集之前有一個正則表達式,則添加正則表達式的等價關係,這將直接跳到最後一個循環。並將這兩種類型的引號添加到主要字符集。這樣,如果在任何時候發現了開始的引用char,則正則表達式將終止並返回。尼斯。 – 2012-03-15 11:36:40

2

蒂姆的解決方案工作得相當好,如果你可以使用環視(其中的Java不支持)。每種情況下單獨

"(\\"|[^"])*"|'(\\'|[^'])*' 

比賽,而是返回兩種情況下:但是,如果你要使用的語言或工具,它不支持環視發現自己,你可以簡單地匹配兩種情況下(雙引號字符串和單引號的字符串)分別作爲整個匹配


無論其

這兩種情況可以犧牲品至少一個不測。如果不仔細看,你可能會覺得應該有在此摘錄比賽:

他轉身坐上他的自行車。「等我完成了這一切後,我會再見到你的。」他說,在開始他的旅程之前回頭看了一會兒。當他進入街道時,這座城市的一個手推車與邁克的自行車相撞。 「天啊!」一位旁觀者驚呼道。

...但也有場比賽,而不是兩個:

"I'll see you later, when I'm done with all this" 
's trolleys collided with Mike' 
"Oh my!" 

這個摘錄只包含ONE比賽:

的鬥爭還沒有結束,但是。 「嘿!」鮑勃大叫。 「你想要什麼?」我反駁道。 「你讓我噁心!」 「我爲什麼要關心?」 「因爲我愛你!」 「你做?」鮑勃停了片刻,然後低聲說道:「不,我不能愛你!」

你能找到那個嗎? :d

't over yet, though. "Hey!" yelled Bob. "What do you want?" I retorted. "I hate your guts!" "Why would I care?" "Because I love you!" "You do?" Bob paused for a moment before whispering "No, I couldn' 

我會建議(如果你是爲使用環視),您考慮做一些額外的檢查(如空格或第一次報價之前類似的積極的回顧後),以確保你不」 t匹配's trolleys collided with Mike'之類的東西 - 儘管如果沒有大量測試,我不會在任何解決方案上投入太多資金。添加(?<=\s|^)要麼表達年初將避免上述情況...即:

(?<=\s|^)(["'])(?:\\.|(?!\1).)*\1     #based on Tim's 

(?<=\s|^)("(\\"|[^"])*"|'(\\'|[^'])*')    #based on my alternative 

我不知道怎麼環視效率相比於非環視,所以兩個以上可能是等價的,或者一個可能比另一個更有效率(?)

+0

這裏有一些好點的代碼騎師,並且確實以這種方式解析英文文本不是明智的。然而,我實際上試圖解析MySQL代碼中的俄文文本(我在上面的代碼中將а-яА-ЯёЁ更改爲a-zA-Z,以便這裏的人員能夠掌握其含義),並且在解析字符串在代碼中,它們當然總是保證被一種引號或另一種引用。 – 2012-03-15 15:41:19