如何在 JavaScript 中的字符串中间进行锚定正则表达式匹配
Posted
技术标签:
【中文标题】如何在 JavaScript 中的字符串中间进行锚定正则表达式匹配【英文标题】:How do I make an anchored regex match in the middle of a string in JavaScript 【发布时间】:2012-08-02 20:52:57 【问题描述】:我找不到让 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 端口,其中每个终端都是一个正则表达式,它在当前解析位置尝试(并锚定在它的前面)。效率是一个问题。例如,在我的起点使用输入的子字符串副本将是最糟糕的解决方案。
我能想到的一个解决方案是将匹配项的“索引”值与我设置的 lastIndex 值进行比较,看看它是否在开始时匹配。这会降低 '^' 的效率,但可能不会花费太多,因为 Pegex 正则表达式通常很小并且没有括号。
谁能想到更好的解决方案?
【问题讨论】:
那么,您希望正则表达式匹配从字符串中的特定索引开始而不先执行子字符串? 这是一个不错的近似值。 你可能在这里追求虚假的效率。仅从所需索引开始进行手动比较并且不使用正则表达式可能会快得多,因为正则表达式匹配非常慢。你必须测试才能确定。或者,使用substring()
并使用简单的正则表达式而不是避免substring()
的复杂正则表达式可能会更快。
除了整个框架仅基于正则表达式匹配。这是解析 Pegex 本身的Pegex grammar。我不同意动态语言中的正则表达式解析速度很慢(欢迎参考)。我会猜测任何简单(非回溯)正则表达式匹配,都比任何其他两个操作都快。即 a.match(/^b/) 比 a.substr(0,1) == 'b' 快。
你应该在做出假设之前进行测试。在this jsperf 中,substr()
版本比 Chrome 中的正则表达式版本快 8 倍。
【参考方案1】:
匹配 "^.4actualre" 怎么样?
【讨论】:
现在这是个好主意。我将在此基础上跟进一个通用解决方案。【参考方案2】:将字符数跳过到要开始匹配的位置是解决此问题的一个非常好的通用解决方案(恕我直言)。
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 中请求任何字符(包括换行符)的常用方式,那么它可以简单地一次性向前索引。
还有什么好主意吗? :)
【讨论】:
我也提出了这个想法,但我认为它的性能并不比子字符串操作更好 - 正则表达式构造函数的成本很高。顺便说一句,如果你愿意,你仍然可以让r
成为文字以上是关于如何在 JavaScript 中的字符串中间进行锚定正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章
如何使用Javascript选择具有特定文本内容的所有锚标签? [重复]