RegExp匹配10行或更少,这在Ruby和Javascript中是交叉兼容的

时间:2016-10-13 12:51:00

标签: javascript ruby-on-rails ruby regex

我有一个Rails后端支持Node前端,Rails后端的一部分是对字段的验证,我们不会公开并传递给Node前端使用。

我们的大多数验证规则都非常简单,将某些字符列入黑名单等等。

但有一条规则是某个字段可以包含不超过10个新行。

现在,在Ruby中,使用以下内容可以很容易地实现:

/\A(^.*$\r?\n?){0,10}\z/

但是,这与Javascript不兼容,因为字符串和行尾字符的结尾是相同的。

我试过的兼容两者的方法如下:

/\A([^\n]*\n[^\n]*){10,}\z/

虽然这在Node端运行良好,但这似乎是Catastrophic backtracking的情况,好像测试字符串变得太复杂,完成正则表达式需要指数长一些。

我知道如果不使用正则表达式,这将是 lot 更简单,但由于我们的堆栈的当前设置,使用除了{{不支持的任何东西之外的任何东西都不是一个选项。 3}}

任何帮助都会在这里得到高度赞赏,因为我正在把头撞到一堵砖墙上试图解决这个问题!

1 个答案:

答案 0 :(得分:0)

你不能用一个可以在JavaScript和Ruby中运行的正则表达式来做到这一点。使用单个正则表达式匹配验证字符串的全部内容需要字符串开头和字符串结尾锚点。 JavaScript和Ruby使用不兼容的语法。

在JavaScript中,如果未指定^标志以匹配字符串的开头和结尾,则可以使用$/m。 JavaScript不支持\A\z

在Ruby中,您可以使用\A\z来匹配字符串的开头和结尾。 Ruby确实支持^$,但没有选项只在字符串的开头和结尾处进行匹配。它们总是匹配嵌入的换行符。

你的正则表达式陷入灾难性回溯的原因是你在重复组的开头和结尾都有[^\n]*。这意味着在下一次迭代期间,非LF字符可以由第二个[^\n]*或第一个[^\n]*匹配。正则表达式引擎将尝试所有这些排列,这需要永远。

解决方案是在组内只有一个[^\n]*。对于JavaScript:

^[^\n]*(?:\n[^\n]*){0,10}$

对于Ruby:

\A[^\n]*(?>\n[^\n]*){0,10}\z

\n放在组的开头可确保在[^\n]*被回溯时立即失败。在Ruby中,我们可以通过使用原子组来消除大量的回溯。