我有这个正则表达式从文本中提取双字
/[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
如何实现此输出?据我了解,搜索索引移动到第一场比赛结束。我怎样才能将它移回一个单词?
答案 0 :(得分:5)
我使用replace
函数使用了一个小技巧。由于replace
函数循环匹配并允许我们指定函数,因此可能性是无限的。结果将在output
。
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
});
由于输出包含输入字符串中的重叠部分,因此当我们使用 预测 匹配当前单词时,不必使用下一个单词 1
正则表达式/[A-Za-z]+(?=(\s[A-Za-z]+))/g
与我上面所说的完全一样:它只会在[A-Za-z]+
部分(正则表达式的开头)一次只消耗一个字,并且预测下一个单词(?=(\s[A-Za-z]+))
2 ,还捕获匹配的文本。
传递给replace
函数的函数将接收匹配的字符串作为第一个参数,并在后续参数中接收捕获的文本。 (还有更多 - 检查documentation - 我在这里不需要它们)。由于前瞻是零宽度(输入不被消耗),所以整个匹配也方便地成为第一个单词。前瞻中的捕获文本将进入第二个参数。
请注意,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]);
}
在支持可变宽度负面后视的其他正则表达式中,可以检索前一个单词,但JavaScript正则表达式不支持负面后卫!。
(?=pattern)
是预见的语法。
String.match
,因为它在使用g
标志时会忽略捕获组。正则表达式中必须使用捕获组,因为我们需要环顾四周以避免消耗输入并匹配重叠文本。
答案 1 :(得分:4)
可以在没有正则表达式的情况下完成
"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;})
答案 2 :(得分:2)
这是一个非正则表达式解决方案(这不是一个常见的问题)。
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;
}
传递你的字符串然后你得到一个数组。
旁注:如果您担心输入中的非单词(为正则表达式做出判断!),您可以在parts[i]
内的parts[i+1]
和for
上运行测试环。如果测试失败:请勿将它们推到out
。
答案 3 :(得分:1)
你可能喜欢的方式就是这个:
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及以下版本不支持以下功能:
但它们很容易变质。或者for
可以轻松实现相同的功能。
答案 4 :(得分:0)
我们走了:
你仍然不知道正则表达式内部指针是如何工作的,所以我将用一个小例子向你解释:
Mary had a little lamb
使用此正则表达式/[A-Za-z]+\s[A-Za-z]+/g
此处,正则表达式的第一部分:[A-Za-z]+
将与Mary
匹配,因此指针将位于y
Mary had a little lamb
^
在下一部分(\s[A-Za-z]+
)中,它将匹配一个空格,后跟另一个单词,所以......
Mary had a little lamb
^
指针将是单词had
结束的位置。所以这就是你的问题,你正在增加正则表达式的内部指针而不想要,这是如何解决的? Lookaround是你的朋友。使用lookarounds(lookahead和lookbehind),您可以在不增加正则表达式的主内部指针的情况下遍历文本(它将使用另一个指针)。
所以最后,符合你想要的正则表达式是:([A-Za-z]+(?=\s[A-Za-z]+))
说明:
唯一认为你不知道正则表达式是(?=\s[A-Za-z]+)
部分,这意味着[A-Za-z]+
必须后跟一个单词,否则正则表达式不会匹配。这正是你想要的东西,因为内部指针不会增加并且会匹配每一个字但是最后一个,因为最后一个字不会跟着一个字。
然后,一旦你有了,你只需要替换你现在所做的一切。
这里有一个工作示例,DEMO
答案 5 :(得分:0)
完全钦佩'预见'的概念,我仍然提出pairwise
函数(demo),因为它真的是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);
});