【问题标题】:JavaScript: avoiding empty strings with String.split, and regular expression precedenceJavaScript:避免使用 String.split 和正则表达式优先级的空字符串
【发布时间】:2013-11-23 22:49:33
【问题描述】:

我正在创建一个语法荧光笔,并且我正在使用 String.split 从输入字符串创建标记。 第一个问题是 String.split 会创建大量的空字符串,这会导致一切都比原本可能的速度慢很多。

例如,"***".split(/(\*)/) -> ["", "*", "", "*", "", "*", ""]。 有没有办法避免这种情况?

另一个问题是正则表达式本身的表达式优先级。 假设我正在尝试解析 C 风格的多行注释。 即/* comment */。 现在让我们假设输入字符串是"/****/"。 如果我使用以下正则表达式,它会起作用,但会产生很多额外的标记(以及所有那些空字符串!)。

/(\/\*|\*\/|\*)/

更好的方法是读取/**/,然后在一个令牌中读取所有其余的*。 也就是说,上述字符串的更好结果是["/*", "**", "*/"]。 但是,当使用应该这样做的正则表达式时,我得到了不好的结果。 正则表达式是这样的:/(\/\*|\*\/|\*+)/

这个表达式的结果是:["/*", "***", "/"]。 我猜这是因为最后一部分是贪婪的,所以它从另一部分窃取了比赛。

我找到的唯一解决方案是制作一个否定的前瞻表达式,如下所示:

/(\/\*|\*\/|\*+(?!\/)/

这给出了预期的结果,但与另一个相比它很慢,这对大字符串有影响。

这些问题有解决方案吗?

【问题讨论】:

  • "****".split().join().split('');我知道这可能不是你需要的。但似乎有效。

标签: javascript regex split tokenize


【解决方案1】:

使用lookahed避免空匹配:

arr = "***".split(/(?=\*)/);
//=> ["*", "*", "*"]

或使用filter(Boolean) 丢弃空匹配项:

arr = "***".split(/(\*)/).filter(Boolean);
//=> ["*", "*", "*"]

【讨论】:

  • 遗憾的是,前瞻不允许我在同一个令牌中获得多个东西,例如“***”作为上例中的一个标记。我之前使用了 filter(),但是额外的数组遍历实际上使整个代码比在跳过空字符串时进行一次迭代时要慢。
  • Anu -- 很抱歉打扰你,但你能解释一下或指向一个解释 .filter(Boolean) 概念的资源吗?空字符串是否返回为 false 等。我对你的用法有点困惑。
  • 空字符串在布尔表达式中计算为假。
  • arr = "***".split('');也可用于标记字符串的各个字符。
  • @anubhava 您正在回复 7 年前的回答 :) 我不记得当时我最终做了什么,但归根结底,使用正则表达式进行标记并不是最好,更好地为您想要的任何输入制作特定的标记器(例如逐个字符迭代并知道标记何时开始/结束),它比正则表达式更快,更有效
【解决方案2】:

通常你使用match而不是split进行标记:

> str = "/****/"
"/****/"
> str.match(/(\/\*)(.*?)(\*\/)/)
["/****/", "/*", "**", "*/"]

还要注意非贪婪修饰符? 是如何解决第二个问题的。

【讨论】:

  • 我正在对巨大的字符串进行标记,C 风格的多行注释只是一个示例,该正则表达式如何与其余的匹配? (其余为 {}()[]+-/&^=! 等等)。同时,我刚刚停止使用 greedy 修饰符抓取所有 *,而其余的标记确实使用它。最坏的情况是当有很多 * 时,但由于它们通常不多,我想我可以忍受。作为记录,这目前是我的正则表达式:/[ \t]+|\[+|\]+|\{+|\}+|\(+|\)+|\++|\-+|\*|\/+|<+|>+|&+|\|+|=+|!+|\\/
  • @user2503048: 好吧,javascript中有很多语法高亮,也许你可以从研究它们的源代码开始?您的正则表达式看起来不是最理想的。
猜你喜欢
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 2012-02-07
  • 1970-01-01
  • 2014-09-30
相关资源
最近更新 更多