簡體   English   中英

JavaScript正則表達式中的多個嵌套匹配項

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

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