我有这个正则表达式来从文本中提取双单词 /[A-Za-z]+\s[A-Za-z]+/g 这个示例文本 Mary had a little lamb 我的输出是 [0] - Mary had; [1] - a little; 而我的预期输出是这样的: [0] - Mary had; [1] - had a; [2] - a little; [3] - little lamb 我如何才能实现这个输出?根据我的理解,搜索的索引移动到第一个匹配的末尾。我怎么能把它往后移一个字呢?
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
});
console.log(output);
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]);
}
console.log(output);
function pairs(str) {
var parts = str.split(" "), out = [];
for (var i=0; i < parts.length - 1; i++)
out.push([parts[i], parts[i+1]].join(' '));
return out;
}
console.log(pairs("Mary had a little lamb"));
var s = "Mary had a little lamb";
console.log(
// 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及以下版本不支持以下功能:
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);
});
6条答案
按热度按时间7gyucuyw1#
滥用String.replace函数
我使用
replace
函数的一个小技巧。由于replace
函数循环匹配并允许我们指定一个函数,因此可能性是无限的。结果为output
。由于输出包含输入字符串中的重叠部分,因此当我们使用 * look-ahead *1匹配当前单词时,有必要不消耗下一个单词。
正则表达式
/[A-Za-z]+(?=(\s[A-Za-z]+))/g
的作用与我上面所说的完全一样:它一次只消耗[A-Za-z]+
部分(regex的开始)的一个单词,并前瞻下一个单词(?=(\s[A-Za-z]+))
2,还 * 捕获 * 匹配的文本。传递给
replace
函数的函数将接收匹配的字符串作为第一个参数,并在后续参数中接收捕获的文本。(还有更多-检查文档-我不需要他们在这里)。由于look-ahead是 zero-width(不消耗输入),因此整个匹配也是第一个单词。look-ahead中的捕获文本将进入第二个参数。使用RegExp.exec正确解决
请注意,
String.replace
函数会产生替换开销,因为根本不使用替换结果。如果这是不可接受的,您可以在循环中使用RegExp.exec
函数重写上面的代码:脚注
1.在其他支持可变宽度负向后查找的正则表达式中,可以检索前一个单词,但JavaScript正则表达式不支持负向后查找!.
(?=pattern)
是look-ahead的语法。附录
这里不能使用
String.match
,因为当使用g
标志时,它会忽略捕获组。捕获组在正则表达式中是必要的,因为我们需要查找以避免消耗输入和匹配重叠文本。xeufq47z2#
这可以在没有regexp的情况下完成
6mw9ycah3#
这里有一个非正则表达式的解决方案(这不是一个真正的常规问题)。
旁注:如果您担心输入中的非单词(使用正则表达式!)您可以在
for
循环中对parts[i]
和parts[i+1]
运行测试。如果测试失败:别把他们推到out
上。axzmvihb4#
你可能喜欢的一种方式可能是这样的:
如果你在你的控制台上运行这个命令,你会看到
["Mary had", "had a", "a little", "little lamb"]
。通过这种方式,您可以保留原始的正则表达式,并可以在其中做其他您想要的事情。虽然有一些代码围绕它,使它真正工作。
顺便说一下,这段代码不是跨浏览器的。IE8及以下版本不支持以下功能:
但它们很容易 Flink 。同样的功能也可以通过
for
轻松实现。4ngedf3f5#
开始吧
你仍然不知道正则表达式内部指针是如何工作的,所以我将用一个小例子来解释它:
Mary had a little lamb
与此正则表达式/[A-Za-z]+\s[A-Za-z]+/g
下面是正则表达式的第一部分:
[A-Za-z]+
将匹配Mary
,因此指针将位于y
的末尾在下一部分(
\s[A-Za-z]+
)中,它将匹配一个空格,后面跟着另一个单词,所以...指针将位于单词
had
结束的位置。所以这就是你的问题,你在不想的情况下增加了正则表达式的内部指针,这是如何解决的?环顾四周是你的朋友。有了lookarounds(lookahead和lookbehind),你就可以遍历你的文本,而不需要增加正则表达式的主内部指针(它会使用另一个指针)。所以在最后,匹配你想要的正则表达式将是:
([A-Za-z]+(?=\s[A-Za-z]+))
说明:
你唯一不知道的正则表达式是
(?=\s[A-Za-z]+)
部分,这意味着[A-Za-z]+
后面必须有一个单词,否则正则表达式将不匹配。这正是你想要的,因为interal指针不会增加,并且会匹配除了最后一个单词之外的每个单词,因为最后一个单词后面不会有单词。然后,一旦你有了它,你只需要替换你现在做的任何事情。
这里有一个工作示例DEMO
kse8i1jr6#
出于对“look-ahead”概念的充分赞赏,我仍然建议使用
pairwise
函数(demo),因为对字符流进行标记化实际上是Regex的任务,而如何处理标记取决于业务逻辑。至少我是这么认为的遗憾的是,JavaScript还没有成对的,但是这可以做到: