为什么带有包含捕获组的正则表达式的string.split返回一个以空字符串结尾的数组?

Pim*_*mgd 22 javascript regex string split

我想在第一个冒号上分割一个输入字符串,它仍然在同一行后面有字符.

为此,我使用正则表达式 /:(.+)/

所以给了字符串

aaa:
bbb:ccc
Run Code Online (Sandbox Code Playgroud)

我期待输出

["aaa:\nbbb", "ccc"]
Run Code Online (Sandbox Code Playgroud)

并给出了字符串

aaa:bbb:ccc
Run Code Online (Sandbox Code Playgroud)

我期待输出

["aaa", "bbb:ccc"]
Run Code Online (Sandbox Code Playgroud)

然而,当我实际运行这些命令时,我得到了

["aaa:\nbbb", "ccc", ""]
["aaa", "bbb:ccc", ""]
Run Code Online (Sandbox Code Playgroud)

作为输出.

所以不知何故,javascript在数组的末尾添加一个空字符串.

我已经检查了文档String.split,虽然它确实提到如果你string.split对一个带有指定分隔符的空字符串执行,你将得到一个包含1个空字符串的数组(而不是空数组).它没有提到输出中总是有一个空字符串,或者警告说如果你犯了一个常见的错误或某些东西,你可能会得到这个结果.

我知道我的输入字符串是否在末尾有一个冒号或类似的东西; 然后它在冒号处分裂,其余的匹配是空字符串.这是在使用正则表达式拆分字符串以使其成为没有空元素的数组时提到的问题- 但我没有这个问题,因为我的输入字符串不以我的分隔符结束.

我知道在我的情况下快速解决方案只是简单地限制匹配量,通过"aaa:bbb:ccc".split(/:(.+)/, 2),但我仍然很好奇:

为什么这个string.split调用返回一个以空字符串结尾的数组?

Pei*_*ayz 19

如果我们将正则表达式更改为/:.+/并对其执行拆分,则会得到:

["aaa", ""]
Run Code Online (Sandbox Code Playgroud)

这是正确的,因为正则表达式匹配:bbb:ccc.如果您要手动拆分该字符串,并为您提供相同的输出.

>>> 'aaa:bbb:ccc'.split(':bbb:ccc')
['aaa', '']
Run Code Online (Sandbox Code Playgroud)

添加捕获组只会保存bbb:ccc,但不应更改原始拆分行为.

  • 并帮助解决你的问题:你真正想要的是分裂在一个冒号上,但只有在它后面跟着更多的字符.这被称为"Zero Width Look-Ahead" - 所以你想要的分裂表达式是:`/:(?=.)/` - 如果你只想在第一场比赛时分开,你加上一个限制2分裂函数:''aaa:bbb:ccc'.split(/:(?=.)/,2)` (4认同)

the*_*eye 7

有趣.从这个问题中学到了很多东西.让我分享一下我学到的东西.

Dot与新行不匹配

如果我们考虑它,目的是基于:后跟一个或多个字符来拆分字符串.如果是这种情况,输出应该是

['aaa', '\nbbb:ccc', '']
Run Code Online (Sandbox Code Playgroud)

对?因为.+比赛贪婪.所以,它应该分开:\nbbb:ccc,:匹配:.+匹配\nbbb:ccc.但你得到的实际产量是

[ 'aaa:\nbbb', 'ccc', '' ]
Run Code Online (Sandbox Code Playgroud)

这是因为,.与行终止符不匹配.引用MDN,

(点,小数点)匹配除行终止符之外的任何单个字符:\n,\ r,\ u2028或\ u2029.

所以,:\n不匹配:(.+).这就是为什么它不会在那里打破.如果你真的想要匹配新的行,要么使用[^][\s\S].

例如,

console.log(data.split(/:([\s\S]+)/));
// [ 'aaa:\nbbb', 'ccc', '' ]
console.log(data.split(/:([\s\S]+)/));
// [ 'aaa', '\nbbb:ccc', '' ]
console.log(data.split(/:([^]+)/));
// [ 'aaa', '\nbbb:ccc', '' ]
Run Code Online (Sandbox Code Playgroud)

现在回答你的实际问题,为什么在拆分结束时有一个空字符串.当你削减一条大线时,你会得到多少条线?两条小线.因此,无论何时进行切割,都应该有两个对象.在你的情况下,aaa:\nbbb是第一次剪切,剪切发生的实际位置:ccc,并且由于字符串在那里结束,包括一个空字符串以指示那是字符串的结尾.