JavaScript正则表达式匹配中的移动索引

JavaScript正则表达式匹配中的移动索引,javascript,regex,Javascript,Regex,我用这个正则表达式从文本中提取双字 /[A-Za-z]+\s[A-Za-z]+/g 还有这个示例文本 玛丽有一只小羊羔 我的输出是 [0]-玛丽有;[1] -一点 而我的预期产出是: [0]-玛丽有;[1] -有一个;[2] -一点;[3] -小羊羔 我如何实现这个输出?据我所知,搜索的索引移动到第一个匹配的末尾。如何将其移回一个单词?无需regexp即可完成 "Mary had a little lamb".split(" ") .map(function(item, idx, a

我用这个正则表达式从文本中提取双字

/[A-Za-z]+\s[A-Za-z]+/g

还有这个示例文本

玛丽有一只小羊羔

我的输出是

[0]-玛丽有;[1] -一点

而我的预期产出是:

[0]-玛丽有;[1] -有一个;[2] -一点;[3] -小羊羔


我如何实现这个输出?据我所知,搜索的索引移动到第一个匹配的末尾。如何将其移回一个单词?

无需regexp即可完成

"Mary had a little lamb".split(" ")
      .map(function(item, idx, arr) { 
          if(idx < arr.length - 1){
              return item + " " + arr[idx + 1];
          }
       }).filter(function(item) {return item;})
“玛丽有一只小羊羔”。分开(“”)
.map(功能(项目,idx,arr){
如果(idx
我们开始:

您仍然不知道正则表达式内部指针是如何工作的,因此我将用一个小示例向您解释它:

玛丽用这个正则表达式生了一只小羊羔

这里,正则表达式的第一部分:
[A-Za-z]+
将匹配
Mary
,因此指针将位于
y

Mary had a little lamb
    ^
在下一部分(
\s[A-Za-z]+
)中,它将匹配一个空格,后跟另一个单词,因此

Mary had a little lamb
        ^
指针将位于单词
had
的结尾处。这就是你的问题,你不需要增加正则表达式的内部指针,这是怎么解决的?环顾四周是你的朋友。使用lookarounds(lookahead和lookahead),您可以遍历文本,而无需增加正则表达式的主要内部指针(它将使用另一个指针)

因此,最后,与您想要的匹配的正则表达式是:
([A-Za-z]+(?=\s[A-Za-z]+)

说明:

唯一你不知道的正则表达式是
(?=\s[A-Za-z]+)
部分,这意味着
[A-Za-z]+
后面必须跟一个单词,否则正则表达式将不匹配。这正是你想要的,因为内部指针不会增加,会匹配每个单词,但最后一个单词,因为最后一个单词后面不会跟一个单词

然后,一旦你做到了,你只需要更换你现在所做的一切


这里有一个工作示例,

这里是一个非正则表达式解决方案(这不是一个真正的常规问题)

函数对(str){
var parts=str.split(“”),out=[];
对于(变量i=0;i
传递字符串,就可以得到一个数组


旁注:如果您担心输入中的非单词(为正则表达式打个比方!),您可以在
for
循环中的
部分[i]
部分[i+1]
上运行测试。如果测试失败:不要滥用String.replace函数将它们推到
out

var output = [];
var str = "Mary had a little lamb";
str.replace(/[A-Za-z]+(?=(\s[A-Za-z]+))/g, function ($0, $1) {
    output.push($0 + $1);
    return $0; // Actually we don't care. You don't even need to return
});
我使用了一个小技巧来使用这个函数。由于
replace
函数通过匹配循环并允许我们指定函数,因此可能性是无限的。结果将显示在
输出中

var output = [];
var str = "Mary had a little lamb";
str.replace(/[A-Za-z]+(?=(\s[A-Za-z]+))/g, function ($0, $1) {
    output.push($0 + $1);
    return $0; // Actually we don't care. You don't even need to return
});
由于输出包含输入字符串中的重叠部分,因此在使用look-ahead1匹配当前单词时,不必使用下一个单词

正则表达式
/[A-Za-z]+(?=(\s[A-Za-z]+)/g
的功能与我上面所说的完全相同:它一次只使用
[A-Za-z]+
部分(正则表达式的开头)的一个单词,然后查找下一个单词
(?=(\s[A-Za-z]+)
2,并捕获匹配的文本

传递给
replace
函数的函数将接收匹配的字符串作为第一个参数,并在后续参数中接收捕获的文本。(还有更多-检查-我这里不需要它们)。因为前瞻是零宽度(输入不被消耗),所以整个匹配也很方便地成为第一个字。前瞻中的捕获文本将进入第二个参数

使用RegExp.exec的正确解决方案 请注意,
String.replace
函数会产生替换开销,因为根本不使用替换结果。如果这是不可接受的,您可以在循环中使用
RegExp.exec
函数重写上述代码:

var output = [];
var str = "Mary had a little lamb";
var re = /[A-Za-z]+(?=(\s[A-Za-z]+))/g;
var arr;

while ((arr = re.exec(str)) != null) {
    output.push(arr[0] + arr[1]);
}
脚注
  • 在另一种风格的regex中,它支持可变宽度的负lookbehind,可以检索前面的单词,但是JavaScript regex不支持负lookbehind

  • (?=pattern)
    是前瞻的语法

  • 附录
    此处不能使用
    String.match
    ,因为在使用
    g
    标志时,它会忽略捕获组。在正则表达式中,捕获组是必需的,因为我们需要环顾四周,以避免使用输入并匹配重叠的文本。

    您可能喜欢的一种方法是:

    var s = "Mary had a little lamb";
    
    // Break on each word and loop
    s.match(/\w+/g).map(function(w) {
    
        // Get the word, a space and another word
        return s.match(new RegExp(w + '\\s\\w+'));
    
    // At this point, there is one "null" value (the last word), so filter it out
    }).filter(Boolean)
    
    // There, we have an array of matches -- we want the matched value, i.e. the first element
    .map(Array.prototype.shift.call.bind(Array.prototype.shift));
    
    如果您在控制台中运行此命令,您将看到
    [“Mary had”,“had a”,“a little”,“little lamb”]

    通过这种方式,您可以保留原始正则表达式,并可以在其中执行其他您想要的操作。虽然有一些代码围绕它,使它真正的工作

    顺便说一下,这段代码不是跨浏览器的。IE8及以下版本不支持以下功能:

    • Array.prototype.filter
    • Array.prototype.map
    • Function.prototype.bind

    但它们很容易闪烁。或者同样的功能也可以通过
    for

    轻松实现。出于对“向前看”概念的充分赞赏,我仍然提出了一个
    成对的
    函数(),因为将字符流标记化实际上是Regex的任务,如何使用标记取决于业务逻辑。至少,这是我的看法

    遗憾的是,Javascript还没有成对出现,但这可以做到:

    function pairwise(a, f) {
      for (var i = 0; i < a.length - 1; i++) {
         f(a[i], a[i + 1]);
      }
    }
    
    var str = "Mary had a little lamb";
    
    pairwise(str.match(/\w+/g), function(a, b) {
      document.write("<br>"+a+" "+b);
    });
    
    ​
    
    <代码