[英]Tolerate certain characters in RegEx
我正在编写一种消息格式解析器,该解析器具有(尤其是)解析链接的功能。 这种特定情况需要解析<url|linkname>
from的链接,然后仅用linkname
替换该文本。 这里的问题是, url
或linkname
在任何位置的任何位置都可能包含或不包含\\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。 这方面的一个怪癖,即它要求:
, =
, !
即使在(?:...)
, (?=...)
, (?!...)
表达式之外也要转义的字符。 通过在处理之前将它们转义来解决此问题。
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.