簡體   English   中英

允許RegEx中的某些字符

[英]Tolerate certain characters in RegEx

我正在編寫一種消息格式解析器,該解析器具有(尤其是)解析鏈接的功能。 這種特定情況需要解析<url|linkname> from的鏈接,然后僅用linkname替換該文本。 這里的問題是, urllinkname在任何位置的任何位置都可能包含或不包含\\1\\2字符(盡管每個字符最多為一個)。 我想匹配模式,但保留“無效”字符。 這個問題為linkname解決了自己,因為該模式的一部分就是([^\\n+]) ,但是url片段由一個更復雜的模式匹配,更具體地說是is.js的URL驗證模式。 手動修改整個模式以容忍[\\1\\2]到處都是不容易的,而且我需要該模式來保留那些用於跟蹤目的的字符(因此,我不能僅僅只是.replace(/\\1|\\2/g, "")匹配之前)。

如果無法進行這種匹配,是否有某種自動方法可以可靠地修改RegExp,以在每個字符匹配之間添加[\\1\\2]{0,2} ,向所有[chars]匹配添加\\1\\2 ,等等。 。

這是從is.js提取的url模式:

/(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?/i

該模式針對我的目的和<url|linkname>格式進行了如下調整:

let namedUrlRegex = /<((?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?)\|([^\n]+)>/ig;

此處使用的代碼是: JSFiddle

澄清示例( ...表示上方的namedUrlRegex變量, $2是捕獲linkname的捕獲組):

Current behavior:
"<googl\1e.com|Google>".replace(..., "$2") // "<googl\1e.com|Google>" WRONG
"<google.com|Goo\1gle>".replace(..., "$2") // "Goo\1gle"              CORRECT
"<not_\1a_url|Google>".replace(..., "$2") // "<not_\1a_url|Google>"   CORRECT

Expected behavior:
"<googl\1e.com|Google>".replace(..., "$2") // "Google" (note there is no \1)
"<google.com|Goo\1gle>".replace(..., "$2") // "Goo\1gle"
"<not_\1a_url|Google>".replace(..., "$2") // "<not_\1a_url|Google>"

注意\\1的相同規則適用於\\2\\1\\2\\1...\\2\\2...\\1

上下文:用於將WYSIWYG編輯器中的字符串規范化為將要顯示的長度/內容,從而保留當前選擇的位置(用\\1\\2表示,以便在解析后可以將其還原)。 如果“插入符號”被完全刪除(例如,如果光標位於鏈接的URL中),它將選擇整個字符串。 一切正常,除了選擇在URL片段中開始或結束時。

編輯澄清 :我要改變的段在一個字符串,如果它遵循的格式<url|linkname>其中url的URL模式匹配(容忍\\1\\2 )和linkname由非\\n字符。 如果<...|...>字符串中不滿足此條件,則應按照上述not_a_url示例將其保持不變

我最終制作了一個與表達式中所有“符號”匹配的RegEx。 這方面的一個怪癖,即它要求:=! 即使在(?:...)(?=...)(?!...)表達式之外也要轉義的字符。 通過在處理之前將它們轉義來解決此問題。

Fiddle

let r = /(\\.|\[.+?\]|\w|[^\\\/\[\]\^\$\(\)\?\*\+\{\}\|\+\:\=\!]|(\{.+?\}))(?:((?:\{.+?\}|\+|\*)\??)|\??)/g;

let url = /((?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?)/

function tolerate(regex, insert) {
    let first = true;
        // convert to string
    return regex.toString().replace(/\/(.+)\//, "$1").
        // escape :=!
        replace(/((?:^|[^\\])\\(?:\\)*\(\?|[^?])([:=!]+)/g, (m, g1, g2) => g1 + (g2.split("").join("\\"))).
        // substitute string
        replace(r, function(m, g1, g2, g3, g4) {
            // g2 = {...} multiplier (to prevent matching digits as symbols)
            if (g2) return m;
            // g3 = multiplier after symbol (must wrap in parenthesis to preserve behavior)
            if (g3) return "(?:" + insert + g1 + ")" + g3;
            // prevent matching tolerated characters at beginning, remove to change this behavior
            if (first) {
                first = false;
                return m;
            }
            // insert the insert
            return insert + m;
        }
    );
}

alert(tolerate(url, "\1?\2?"));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM