[英]Multiple nested matches in JavaScript Regular Expression
嘗試編寫正則表達式以匹配GS1條形碼模式( https://en.wikipedia.org/wiki/GS1-128 ),其中包含2個或更多這些模式,這些模式具有標識符,后跟一定數量的數據字符。
我需要與此條形碼匹配的東西,因為它包含2個標識符和數據模式:
人類可讀與parens中的標識符:(01)12345678901234(17)501200
實際數據: 011234567890123417501200
但是當只有一個模式時, 不應匹配此條形碼:
人類可讀:(01)12345678901234
實際數據: 0112345678901234
似乎以下應該有效:
var regex = /(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6})){2,}/g; var str = "011234567890123417501200"; console.log(str.replace(regex, "$4")); // matches 501200 console.log(str.replace(regex, "$1")); // no match? why?
出於一些奇怪的原因,一旦我刪除{2,}
它就可以了,但是我需要{2,}
以便它只返回匹配,如果有多個匹配。
// Remove {2,} and it will return the first match var regex = /(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6}))/g; var str = "011234567890123417501200"; console.log(str.replace(regex, "$4")); // matches 501200 console.log(str.replace(regex, "$1")); // matches 12345678901234 // but then the problem is it would also match single identifiers such as var str2 = "0112345678901234"; console.log(str2.replace(regex, "$1"));
我如何使這項工作如果只有一組匹配組,它將只匹配和拉取數據?
謝謝!
對於Perl兼容的正則表達式(PCRE),您的RegEx在邏輯上和語法上都是正確的。 我認為您面臨的問題是JavaScript存在重復捕獲組的問題。 這就是為什么一旦取出{2,}
,RegEx就能正常工作。 通過添加量詞,JavaScript將確保僅返回最后一個匹配。
我建議刪除{2,}
量詞,然后以編程方式檢查匹配。 我知道這不是理想的,誰是正則表達式的忠實粉絲,但是這就是生活 。
請參閱下面的代碼:
var regex = /(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6}))/g; var str = "011234567890123417501200"; // Check to see if we have at least 2 matches. var m = str.match(regex); console.log("Matches list: " + JSON.stringify(m)); if (m.length < 2) { console.log("We only received " + m.length + " matches."); } else { console.log("We received " + m.length + " matches."); console.log("We have achieved the minimum!"); } // If we exec the regex, what would we get? console.log("** Method 1 **"); var n; while (n = regex.exec(str)) { console.log(JSON.stringify(n)); } // That's not going to work. Let's try using a second regex. console.log("** Method 2 **"); var regex2 = /^(\\d{2})(\\d{6,})$/; var arr = []; var obj = {}; for (var i = 0, len = m.length; i < len; i++) { arr = m[i].match(regex2); obj[arr[1]] = arr[2]; } console.log(JSON.stringify(obj)); // EOF
我希望這有幫助。
原因是捕獲組僅給出該特定組的最后一個匹配。 想象一下,你的序列中有兩個條形碼具有相同的標識符01
...現在很明顯$1
不能同時引用這兩個條形碼。 捕獲組僅保留第二次出現。
一種直接的方式,但不是那么優雅,是刪除{2,}
,而是重復整個正則表達式模式以匹配第二個條形碼序列。 我認為你還需要使用^
(字符串錨的開頭)來確保匹配位於字符串的開頭,否則你可能會在無效序列的中途找到一個標識符。 在重復的正則表達式模式之后,您還應該添加.*
如果您想要忽略第二個序列之后的任何內容,並且在使用replace
時不會讓它返回給您。
最后,由於您不知道第一次和第二次匹配將找到哪個標識符,您需要在replace
重現$1$2$3$4
,因為知道這四個中只有一個是非空字符串。 第二場比賽相同: $5$6$7$8
。
以下是應用於示例字符串的改進代碼:
var regex = /^(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6}))(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6})).*/; var str = "011234567890123417501200"; console.log(str.replace(regex, "$1$2$3$4")); // 12345678901234 console.log(str.replace(regex, "$5$6$7$8")); // 501200
如果你還需要匹配第二個條形碼,那么你就無法逃避編寫循環。 僅使用基於正則表達式的replace
,您無法做到這一點。
如果允許循環,那么您可以使用regex#exec
方法。 然后我建議在你的正則表達式中添加一種“catch all”,如果其他標識符都不匹配,它將匹配一個字符。 如果在循環中檢測到這樣的“全部捕獲”匹配,則退出:
var str = "011234567890123417501200"; var regex = /(?:01(\\d{14})|10([^\\x1D]{6,20})|11(\\d{6})|17(\\d{6})|(.))/g; // 1: ^^^^^^ 2: ^^^^^^^^^^^^^ 3: ^^^^^ 4: ^^^^^ 5:^ (=failure) var result = [], grp; while ((grp = regex.exec(str)) && !grp[5]) result.push(grp.slice(1).join('')); // Consider it a failure when not at least 2 matched. if (result.length < 2) result = []; console.log(result);
第一個例子
$ 1 $ 2 $ 3 $ 4的例子不知道為什么在矩陣:)
但你看$ 1 - > abc $ 2 - > def $ 3 - > ghi $ 4 - > jkl
// $1 $2 $3 $4 var regex = /(abc)|(def)|(ghi)|(jkl)/g; var str = "abcdefghijkl"; // test console.log(str.replace(regex, "$1 1st ")); console.log(str.replace(regex, "$2 2nd ")); console.log(str.replace(regex, "$3 3rd ")); console.log(str.replace(regex, "$4 4th "));
第二個例子
在這里混合有缺陷
// $1 $2 $3 $4 var regex = /((abc)|(def)|(ghi)|(jkl)){2,}/g; var str = "abcdefghijkl"; // test console.log(str.replace(regex, "$1 1st ")); console.log(str.replace(regex, "$2 2nd ")); console.log(str.replace(regex, "$3 3rd ")); console.log(str.replace(regex, "$4 4th "));
如你所見,有($4)( )( )( )
而不是($1)( )( )( )
。
如果我認為問題是使用外部括號()
令人困惑的'偽'$ 1是4美元。 如果你在外括號()
有一個模式,然后是{2,}
所以在外括號()
它是$ 4但在子模式中有(?:01(\\d{14}))
但它看起來不是$ 1但是有缺陷在這種情況下4美元。 也許這會導致外部括號()中記住的值與第一個記住的值之間的沖突,但在括號內(這是$ 1) 。 這就是為什么它不顯示。 換句話說,你有($ 4($ 1 $ 2 $ 3 $ 4)),這是不正確的。
我添加圖片來表明我的意思。
正如@Damian所說
通過添加量詞,JavaScript將確保僅返回最后一個匹配。
所以4美元是最后一場比賽。
我添加了有用的小測試
var regex = /(?:01(\\d{14})|10(\\x1D{6,20})|11(\\d{6})|17(\\d{6})){2,}/g; var str = "011234567890123417501200"; // test console.log(str.replace(regex, "$1 1st ")); console.log(str.replace(regex, "$2 2nd ")); console.log(str.replace(regex, "$3 3rd ")); console.log(str.replace(regex, "$4 4th "));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.