如何在JavaScript中使一个锚定的正则表达式匹配字符串的中间

4
我希望能够在字符串中间开始匹配JavaScript正则表达式,并使用'^'限定(将正则表达式的开头锚定到我指定的起始点), 但是我找不到方法。
Perl和Python有我需要的功能(尽管它们彼此完全不同)。
在Perl中,我可以这样做:
$s = 'foo bar baz';
$r = qr/\Gbar/;
pos($s) = 4;
print 'OK' if $s =~ $r;

在Python中,我可以做到:

s = 'foo bar baz'
r = r'bar'             # r'^bar' also works
if re.match(r, s[4:]): # re.match implies '^'
    print 'OK'

在JavaScript中(至少在Node.js中),我尝试:
s = 'foo bar baz';
r = /^bar/g;
r.lastIndex = 4;
if (r.exec(s))
    console.log('OK');

这个不起作用。如果我把第二行改成:

r = /bar/g;

然后它确实匹配了,但是它也可以在4之后的任何位置匹配(这不是我想要的)。
背景:我正在处理名为Pegex的多语言解析框架的JavaScript端口,其中每个终端都是在当前解析位置尝试的正则表达式(并锚定到其前面)。效率是一个问题。例如,在我的起始点使用输入的子字符串副本将是最糟糕的解决方案。
我能想到的一个解决方案是将匹配的“index”值与我设置的“lastIndex”值进行比较,以查看它是否在开头匹配。这会丢掉'^'的效率,但可能不会花费太多,因为Pegex regex通常很小且没有回溯。
有人能想到更好的解决方案吗?

2
所以,您想要在字符串中的特定索引处开始正则表达式匹配,而不是先进行子字符串操作? - jfriend00
这是一个不错的近似。 - ingydotnet
你可能在追求一种虚假的效率。从所需的索引开始手动比较可能会更快,而不使用正则表达式,因为正则表达式匹配通常很慢。你必须进行测试才能确定。或者,使用substring()并使用简单的正则表达式可能比避免substring()的复杂正则表达式更快。 - jfriend00
2
在做出假设之前,你应该进行测试。在这个jsperf中,在Chrome浏览器中,substr()版本比正则表达式版本快8倍。 - jfriend00
是的,没错。我认为他的情况可以与这些测试相媲美。 - Bergi
显示剩余4条评论
2个回答

3
“^.{4}actualre”是什么意思呢?

现在这是一个好主意。我会基于此跟进一个通用解决方案。 - ingydotnet

1

跳过要匹配的字符数是解决这个问题的一个非常好的通用方法(在我看来)。

s = 'foo bar baz';                                                          
r = 'bar';                                                                  
p = 4;                                                                      
r = new RegExp('^[\\s\\S]{' + p + '}' + r);                 
if (r.exec(s))                                                              
    console.log('OK');                                                      

我得测试一下这个在大数据上的表现,但我想根据正则表达式的实现方式,它可能会相当不错。例如,如果实现意识到 [\s\S] 是 JS 中请求任何字符(包括换行符)的常用方式,则可以一次性向前索引。

还有其他好主意吗? :)


2
我也想到了这个想法,但我认为它的性能不如子字符串操作 - 正则表达式构造函数的成本很高。顺便说一下,如果你想的话,仍然可以让r成为一个字面量。 - Bergi

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