我需要根据结构化源字符串匹配多行中的多个组。
该字符串的格式为每行一个名称,但还有一些其他值,按以下顺序:
- 每行开始的名称前可以有一个数字;
- 号码和名称之间可能有一些垃圾分隔符;
- 名称可以包含任何字符,包括括号、撇号等符号;
- 括号之间可能有一个代码,名称后面有 3 或 4 个字母(不必担心名称后面可能有 3 或 4 个字母,这种情况不会发生)
- 行尾、换行符之前可能有一个星号。
我需要为每行检索这 4 个组。这就是我正在尝试的:
/^(\d+)?(?:[ \t]?[x:.=]?)[ \t]?(.+?)(?=[ \t]?(\(\w{3,4}\))?[ \t]?(\*))$/igm
要获取号码:
^(\d+)?
要清洁可能的分隔符:
(?:[ \t]?[x:.=]?)
过滤每个组之间的空间:
[ \t]?
名称(以及其余部分):
(.+?(?=[ \t]?(\(\w{3,4}\))?[ \t]?(\*)?))
问题显然出在最后一个。它正在捕捉所有的东西(第 2、3 和 4 组)。正如您所看到的,我正在尝试将最后两个可选组作为正向前瞻,将它们与名称分开。
我做错了什么或者如何更好地实现结果?
编辑
字符串示例:
2 John Smith
3 Messala Oliveira (NMN) *
Mary Pop *
Joshua Junior (pMHH)
我需要什么:
[ "2", "John Smith", "", "" ],
[ "3", "Messala Oliveira", "(NMN)", "*" ],
[ "", "Mary Pop", "", "*" ],
[ "", "Joshua Junior", "(pMHH)", "" ],
最佳答案
您需要使用可选的非捕获组来包装可能存在或不存在的捕获组:
/^(?:(\d+)[ \t]*)?(.*?)(?:[ \t](\(\w{3,4}\)))?(?:[ \t](\*))?$/igm
请参阅regex demo .
详细信息:
^
- 字符串开头(?:(\d+)[\t]*)?
- 可选的非捕获组匹配(\d+)
-(第 1 组)1+ 位数字[\t]*
- 0+ 空格或制表符(如果使用\s
,则 0+ 空格)
(.*?)
- 第 2 组捕获除 linenbreaks 符号之外的任何 0+ 字符,尽可能少(?:[\t](\(\w{3,4}\)))?
- 可选的组匹配[\t]
- 空格或制表符(\(\w{3,4}\))
- 第 3 组捕获(
、3 或 4 个单词字符、)
(?:[\t](\*))?
- 另一个可选组,匹配空格或制表符,并将*
符号捕获到组 4 中。<$
- 字符串结尾。
如果单独测试字符串,[\t]
可以替换为更简单的 \s
:
var regex = /^(?:(\d+)\s*)?(.*?)(?:\s(\(\w{3,4}\)))?(?:\s(\*))?$/i;
var strs = ['2 John Smith','3 Messala Oliveira (NMN) *','Mary Pop *','Joshua Junior (pMHH)'];
for (var i=0; i<strs.length; i++) {
if ((m = regex.exec(strs[i])) !== null) {
var res = [];
if (m[1]) {
res.push(m[1]);
} else res.push("");
res.push(m[2]);
if (m[3]) {
res.push(m[3]);
} else res.push("");
if (m[4]) {
res.push(m[4]);
} else res.push("");
}
console.log(res);
}
关于javascript - 尝试使用 REGEX 过滤字符串中的多个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40069013/