尝试编写正则表达式以匹配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"));
如何使这项工作如此,如果有超过1组匹配组,它只会匹配并提取数据?
谢谢!
答案 0 :(得分:2)
对于Perl兼容的正则表达式(PCRE),您的RegEx在逻辑上和语法上都是正确的。我认为您面临的问题是JavaScript存在重复捕获组的问题。这就是为什么一旦取出{2,}
,RegEx就能正常工作。通过添加量词,JavaScript将确保仅返回 最后一场比赛。
我建议删除{2,}
量词,然后以编程方式检查匹配项。我知道这对于那些忠实于RegEx的人来说并不理想,但 c' est la vie 。
请参阅下面的代码:
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
&#13;
我希望这会有所帮助。
答案 1 :(得分:1)
原因是捕获组仅提供该特定组的最后一场比赛。想象一下,序列中有两个条形码具有相同的标识符01
...现在很明显$1
不能同时引用这两个条形码。捕获组仅保留第二次出现。
一种直截了当但不那么优雅的方法是删除{2,}
,而是重复整个正则表达式模式以匹配第二个条形码序列。我认为你还需要使用^
(字符串锚的开头)来确保匹配位于字符串的开头,否则你可能会在无效序列的中途选择一个标识符。在重复的正则表达式模式之后,如果你想忽略第二个序列后面的任何内容,你还应该添加.*
,而不是在使用replace
时让它回复给你。
最后,由于您不知道第一场和第二场比赛将找到哪个标识符,因此您需要在$1$2$3$4
中重现replace
,因为您知道这四个中只有一个会是一个非空字符串。第二场比赛相同:$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
&#13;
如果你还需要匹配第二个条形码,那么你就无法摆脱写一个循环。仅使用基于replace
的正则表达式,您无法做到这一点。
如果允许循环,则可以使用regex#exec
方法。然后,我建议在正则表达式中添加一种&#34; catch all&#34;,如果其他标识符都不匹配,它将匹配一个字符。如果在循环中你发现了这样一个&#34;赶上所有&#34;匹配,退出:
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);
&#13;
答案 2 :(得分:0)
第一个例子
示例$ 1 $ 2 $ 3 $ 4不知道为什么在矩阵:)
但你看到$ 1 - &gt; ABC $ 2 - &gt; def $ 3 - &gt; ghi $ 4 - &gt; 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 "));
&#13;
第二个例子
在这里混合有缺陷的
// $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 "));
&#13;
如您所见,($4)( )( )( )
代替($1)( )( )( )
。
如果我认为问题恰到好处,那么问题就在于外部括号()
令人困惑&#39;伪&#39; 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 "));
&#13;