我试图从字符串中提取数字组。
这些数字可以单独使用,也可以作为\d+ - \d+
格式的范围,而两个数字之间的范围指示可以有所不同,数字可以包含前缀M-
或STR
。这些组在给定的字符串中可以出现1到n次,但如果一个组后跟任何不是数字,空格或上述前缀之一的字符,匹配应该停止,即使之后可以找到更多的数字。
举个例子,以下几行
01
05,07
05, 7
M-01, M-12
311,STR 02
M-56
STR 17
01 - Random String 25-31 Random other string
M-04 Random String 01
M-17,3,148,14 to 31
M-17,3,STR 148,14 to 31 - Random String
M-17,3,148,14- 31 Random, String 02 Random, other string
STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02
应该返回
01
05;07
05;7
01;12
311;02
56
17
01
04
17;3;148;14 to 31
17;3;148;14 to 31
17;3;148;14- 31
17;3;12 to 18;148;14- 31
我使用javascript并且几乎可以通过运行
获得正确的结果var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig
while (result = pattern.exec(line)) {console.log(result)}
但是我无法弄清楚如何在第一个字符串后不匹配数字,即M-17,3,148,14 to 31 - Random string 46 Random string
会返回值17;3;148;14 to 31;46
,而46则不匹配。
我并不真正关心结果的格式,因为无论如何我都会对它们进行消毒,所以'03 '
作为'03'
返回并不重要。或'03 '
。对于数字范围也是如此,15 - 17
可以作为15 - 17
返回,或者像上面的示例一样,使用捕获组来确定上限和下限,但我仍然需要能够分辨如果两个数字是分开的或范围,则5,8,10-12
不能作为5;8;10;12
返回。
我的最终目标是提取每一行中的所有可能值。在我提取了所有数字范围后,我遍历每个结果以获得所有可能的值,例如5,8,10-12将成为5; 8; 10; 11; 12.
如果它在某种程度上是可能的,并且这纯粹是可选的,我也想在最后一个数字范围之后保留字符串,例如STR 14, 23 Some String 18 Some other string
应该14;23
并单独Some String 18 Some other string
返回。
如果有人知道如何解决这个问题,我将不胜感激。
答案 0 :(得分:0)
所以,喝完咖啡后,我想我找到了一个接近解决方案的东西:
function extractNumbers(line){
var str = line.replace(/(?:M-\s?|STR )(\d+)/ig,'$1')
var rightpart = str.match(/([a-x].*)/i)
var leftpart = str.replace(rightpart[1],'')
var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig
while (result = pattern.exec(leftpart)) {console.log(result)}
console.log(rightpart[1])
}
此函数将所有数字范围输出,然后将其余字符串输出到控制台。有可能出现误报,因为它首先替换所有出现的M-和STR后跟一个数字,即使它们出现在字符串的右边部分。在右边部分出现这种确切字符序列的可能性很小,但仍然是......
如果有人对原始问题有答案或者如何消除误报的可能性,我很乐意看到它。
答案 1 :(得分:0)
这是我的尝试。
[
'01',
'05,07',
'05, 7',
'M-01, M-12',
'311,STR 02',
'M-56',
'STR 17',
'01 - Random String 25-31 Random other string',
'M-04 Random String 01',
'M-17,3,148,14 to 31',
'M-17,3,STR 148,14 to 31 - Random String',
'M-17,3,148,14- 31 Random, String 02 Random, other string',
'STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02',
'14 ~ 16',
'Random String 15',
'1to3',
'M-01 to STR 6',
'17 56'
].forEach(function(str) {
var rangeRe = /(?:\s*,\s*)(?:M-|STR )?(\d+)(?:\s*(?:-|~|to)\s*(\d+))?/g,
ranges = [],
lastIndex = 1,
match;
str = ',' + str;
while (match = rangeRe.exec(str)) {
// Push a lower and upper bound onto the list of ranges
ranges.push([+match[1], +(match[2] || match[1])]);
lastIndex = rangeRe.lastIndex;
}
// Log the original string, the ranges and the remainder
console.log([
str.slice(1),
ranges.map(function(pair) {
return pair[0] + '-' + pair[1];
}).join(' ; '),
str.slice(lastIndex)
]);
});

以下是我遵循的规则:
-
,~
或to
分隔,并在分隔符旁边添加任意空格。M-
或STR
作为前缀。前缀和范围之间不允许有额外的空格。,
加上,
任意一侧的任意空格分隔。每个范围都被解析为由下限和上限组成的数组对。对于单个数字范围,两个边界使用相同的值。
我使用了exec
的有状态。循环的每次迭代开始匹配前一个匹配停止的位置。跟踪lastIndex
,以便我们可以生成剩余的随机字符串'最后。
我在开始之前在字符串的前面添加,
。这允许RegExp假设所有范围都以,
开头,从而避免需要第一个范围的特殊情况。
与您发布的一些RegExps的一个主要区别是,我制作了整个'范围分隔符和上限'部分可选作为一个单元,而不是使它们单独可选。结果是,17 56
之类的输入会将56
视为随机字符串'而不是上限。该范围将被视为17-17。