繁体   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