2012-12-15 98 views
6

tl; dr有沒有辦法在ORACLE中將任意正則表達式整合爲一個正則表達式(用於匹配而不是捕獲)?結合(或)任意正則表達式


在我的應用程序收到兩個列表從用戶:

  1. 正則表達式的列表串

  • 名單,我需要輸出的字符串列表在(2)中與(1)中的任何正則表達式都不匹配。 (迭代遍歷(2)中的所有字符串;對於每個字符串迭代(1)中的所有模式;如果沒有模式匹配字符串,則將它添加到將返回的列表中)但我想知道是否可以將所有模式合併爲一個模式,並讓正則表達式編譯器利用優化機會。

    OR-combine正則表達式的顯而易見的方法顯然是(regex1)|(regex2)|(regex3)|...|(regexN),但我敢肯定,考慮到我無法控制各個正則表達式,這不是正確的做法(例如,它們可能包含所有後退/前向引用)。因此,我想知道你是否可以提出一種更好的方法來結合java中的任意正則表達式。


    注:這只是由上述暗示,但我會讓它明確:我只對匹配字符串 - 我不需要使用捕獲組的輸出。

  • +0

    一個正則表達式匹配字符串的一部分還是匹配整個字符串? – Tomalak

    +0

    @Tomalak由用戶提供的正則表達式應該被允許匹配(2)中的部分字符串 - 特別是在我使用Matcher.find()的天真實現中,看看是否至少有匹配 – CAFxX

    +0

    讓你認爲'regex1 | regex2 | regex3'產生錯誤的結果?你能構建一個它會的情況嗎? – Tomalak

    回答

    4

    一些正則表達式引擎(例如PCRE)具有構造(?|...)。它就像一個非捕獲組,但具有很好的特性,即在每個交替組中都從相同的初始值開始計數。這可能會立即解決您的問題。所以如果切換語言這個任務是你的選擇,那應該可以做到。

    [編輯:事實上,它仍然會引起衝突命名爲捕獲組的問題。實際上,該模式甚至不會編譯,因爲組名不能被重用。]

    否則,您將不得不操縱輸入模式。海德建議重新編號反向引用,但我認爲有一個更簡單的選項:使所有組命名爲組。你可以向你保證這些名字是獨一無二的。

    因此,基本上,對於每個輸入模式,您創建一個唯一的標識符(例如,增加一個ID)。然後最棘手的部分是在模式中找到捕獲組。你將無法用正則表達式來做到這一點。你將不得不自己解析模式。如果您只是遍歷模式字符串,請注意以下幾點:

    • 請注意當您進入和離開字符類時,因爲字符類內部括號是文字字符。
    • 也許最棘手的部分:忽略後跟?:?=?!?<=?<!?>所有打開的括號。此外,還有選項設置圓括號:(?idmsuxU-idmsuxU)(?idmsux-idmsux:somePatternHere),它們也不會捕獲任何內容(當然,這些選項可能有任何子集,它們可以以任意順序排列 - -也是可選的)。
    • 現在你應該只剩下開放的圓括號,這個圓括號既可以是正常的捕獲組,也可以是:(?<name>。最簡單的事情可能是把它們都一視同仁 - 也就是擁有一個數字和一個名字(如果它沒有設置,名字就等於數字)。然後你用(?<uniqueIdentifier-md5hashOfName>這樣的東西重寫所有這些(連字符實際上不是名稱的一部分,你只需要你遞增的數字後面跟着散列 - 因爲散列是固定長度的,不會有任何重複;非常多至少)。確保記住該組最初有哪些號碼和名稱。
    • 每當遇到反斜槓時,有三個選項:
      1. 下一個字符是一個數字。你有一個編號的反向引用。將所有這些數字替換爲k<name>,其中name是您爲該組生成的新組名稱。
      2. 接下來的字符是k<...>。再次將其替換爲相應的新名稱。
      3. 下一個字符是別的。跳過它。它同時處理括號轉義和反斜槓轉義。
    • 我認爲Java可能允許前向引用。在這種情況下,你需要兩次傳球。照顧重新命名所有組。然後更改所有參考。

    一旦你在每個輸入模式上完成了這一步,就可以安全地將它們全部與|合併。除反向引用以外的任何其他功能都不會導致此方法出現問題。至少不會只要你的模式有效。當然,如果你有輸入a(bc)d那麼你有問題。但是,如果你不檢查模式是否可以自行編譯,你會一直這樣做。

    我希望這給你一個正確的方向指針。