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);
});
<代码