如何在JavaScript中使用正则表达式分割字符串?

7
我有这样一段文本结构:
1.6.1 Members................................................................ 12
1.6.2 Accessibility.......................................................... 13
1.6.3 Type parameters........................................................ 13
1.6.4 The T generic type aka <T>............................................. 13

我需要创建JS对象:

{ 
  num:"1.6.1",
  txt:"Members"
},
{ 
  num:"1.6.2",
  txt:"Accessibility"
} ...

这不是问题。

问题在于我想通过正则表达式并使用正向预查来提取值:

通过第一次看到下一个字符为字母进行分割

enter image description here

我尝试过的方法:

'1.6.1 Members........... 12'.split(/\s(?=(?:[\w\. ])+$)/i)

这个工作正常运行:
["1.6.1", "Members...........", "12"] // I don't care about the 12.

但如果我有两个或更多的单词:
'1.6.3 Type parameters................ 13'.split(/\s(?=(?:[\w\. ])+$)/i)

结果为:

["1.6.3", "类型参数................", "13"] //我不在意13。

当然,我可以将它们拼接在一起,但我希望单词能在一起。

问题:

如何改进我的正则表达式以避免拆分单词?

期望的结果:

["1.6.3", "类型参数"]

["1.6.3", "类型参数........"] //稍后我会删除多余的内容

["1.6.3", "类型参数........13"]//稍后我会删除多余的内容

NB

我知道我可以通过空格或其他更简单的方法进行拆分,但出于纯粹的知识追求,我正在寻求改进我的解决方案使用正向先行拆分

完整在线示例:

nb2:

文本中间可能包含大写字母。


嘿Royi,这些解决方案中有哪个对你有用吗?还是你需要任何微调?请注意,我们给你的是Match而不是Split解决方案,因为Match All和Split是同一个硬币的两面,你可以得到相同的数组,但在这种情况下匹配要容易得多。 - zx81
3个回答

3
您可以使用这个正则表达式:
/^(\d+(?:\.\d+)*) (\w+(?: \w+)*)/gm

通过匹配组#1和匹配组#2,您可以获得所需的匹配项。

在线正则表达式演示

更新:对于String#split,您可以使用此正则表达式:

/ +(?=[A-Z\d])/g

正则表达式演示

更新2:由于章节名称中可能会有大写字母,因此需要使用更复杂的正则表达式:

var re = /(\D +(?=[a-z]))| +(?=[a-z\d])/gmi; 
var str = '1.6.3 Type Foo Bar........................................................ 13';
var m = str.split( re );
console.log(m[0], ',', m.slice(1, -1).join(''), ',', m.pop() );

//=> 1.6.3 , Type Foo Bar........................................................ , 13

谢谢您的回复。但是我在我的笔记本中提到了一些内容(再次强调,关于正向先行拆分的纯知识)。 - Royi Namir
1
并不是OP所问的(“使用正向先行断言拆分”),而且也过于复杂了。 - Christoph
1
更新后的答案非常棒,但希望标题中不存在以大写字母开头的单词。 - Paul Chen
@Diryboy没有这样的保证!我会在我的问题中提到它。那么像“T泛型类型”这样的标题呢? - Royi Namir
1
啊,原来你也可以在中间使用大写字母!!需要找到新的分割方法。顺便说一下,我之前的正则表达式也可以处理这种情况。给我一些时间尝试一些不同的String#split方法(如果可能的话)。 - anubhava
显示剩余7条评论

2

编辑:由于你在要求中增加了1.6.1 .net 4.5框架...,我们可以调整答案如下:

^([\d.]+) ((?:[^.]|\.(?!\.))+)

如果你想在标题中允许最多三个连续的点,比如1.6.1 She said... Boo!...........,那么只需进行简单的调整(使用{3}量词)即可:

^([\d.]+) ((?:[^.]|\.(?!\.{3}))+)

Original:

^([\d.]+) ([^.]+)

正则表达式演示中,查看右侧窗格中的Groups。
要检索组1和组2,可以使用以下类似语句:
var myregex = /^([\d.]+) ((?:[^.]|\.(?!\.))+)/mg;
var theMatchObject = myregex.exec(yourString);
while (theMatchObject != null) {
    // the numbers: theMatchObject[1]
    // the title: theMatchObject[1]
    theMatchObject = myregex.exec(yourString);
}

输出

Group 1     Group 2
1.6.1       Members
1.6.2       Accessibility
1.6.3       Type parameters
1.6.4       The T generic type aka <T>**
1.6.1       The .net 4.5 framework

解释

  • ^ 表示我们在行首
  • 括号([\d.]+) 捕获数字和小数点至第一组
  • 括号((?:[^.]|\.(?!\.))+) 捕获至第二组...
  • [^.] 表示一个不是句点的字符,| 或者...
  • \.(?!\.) 表示一个句点但后面不跟着句点...
  • + 表示一次或多次

这确实是最简单的方法。 - Casimir et Hippolyte
那是一个简单的调整... 完成了。 :) - zx81
此外,还添加了额外的调整,以防您想在标题中允许最多三个点的序列,例如 1.6.1 She said... Boo!...........,并提供完整的说明。 - zx81
Casimir的解决方案是最短的,但由于我明确要求使用正向先行断言,我选择了Anubhava的解决方案ps +1。 - Royi Namir
你可以选择任何你喜欢的,但现在只有我的能够与 1.6.1 .net 4.5框架... 或者 1.6.1 她说... Boo!........... 兼容,对吧? :) - zx81

1
您也可以使用这个模式:
var myStr = "1.6.1 Members................................................................ 12\n1.6.2 Accessibility.......................................................... 13\n1.6.3 Type parameters........................................................ 13\n1.6.4 The T generic type aka <T>............................................. 13";

console.log(myStr.split(/ (.+?)\.{2,} ?\d+$\n?/m));

关于前瞻方式:

我不认为这是可能的。因为跳过一个字符(在这里是两个单词之间的空格)的唯一方法是在先前出现空格的情况下匹配它。换句话说,您利用了字符不能匹配超过一次的事实。

但是,如果除了您想要拆分的空格之外,整个模式都被包含在前瞻中,并且由于前瞻中匹配的子字符串不是匹配结果的一部分(换句话说,它只是检查,相应的字符不会被正则表达式引擎吃掉),您无法跳过下一个空格,正则表达式引擎将继续进行直到下一个空格字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接