[英]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.