8

在 Scala 的解析器组合器(特别是JavaTokensParser)中有一个定义stringLiteral匹配类似 Java 的字符串。

def stringLiteral: Parser[String] =
              ("\""+"""([^"\p{Cntrl}\\]|\\[\\'"bfnrt]|\\u[a-fA-F0-9]{4})*"""+"\"").r

不幸的是,这个正则表达式不适用于长字符串。有谁知道一个可重用的实现,或者对正则表达式的修改更节省空间?

4

1 回答 1

3

有趣的问题!!

只是玩弄这个,并想出了以下内容:

val r = ("\"" + "(?:[^\"\\p{Cntrl}\\\\]*|(?:\\\\(?:[\\\\'\"bfnrt]|u[a-fA-F0-9]{4}))*)*" + "\"").r

注意:上面的正则表达式是从第一个版本中修复的……前导 '\' 和尾随字符都需要重复,而不仅仅是我原来的尾随字符!

编辑:找到一个更有效的正则表达式。使用以下内容,它可以解析最多 950\\ns对的字符串,而原始的只能解析 556,至少在我的默认配置中是这样。

val r = ("\"" + "(?:[^\"\\p{Cntrl}\\\\]*|\\\\[\\\\'\"bfnrt]|\\\\u[a-fA-F0-9]{4})*" + "\"").r

编辑2:根据@schmmd 的评论,我有一个更好的正则表达式。这一个可以解析2500个\ns酷刑案例。秘诀是使用贪婪所有格修饰符,这基本上关闭了回溯的需要,因此也关闭了递归。

val r = (""""([^"\p{Cntrl}\\]*+(?:\\[\\'"bfnrt])*+(?:\\u[a-fA-F0-9]{4})*+)*+"""").r

解决方案的本质是在每次匹配某些东西时尽可能多地咀嚼。

scala> val r = (""""([^"\p{Cntrl}\\]*+(?:\\[\\'"bfnrt])*+(?:\\u[a-fA-F0-9]{4})*+)*+"""").r
r: scala.util.matching.Regex = "([^"\p{Cntrl}\\]*+(?:\\[\\'"bfnrt])*+(?:\\u[a-fA-F0-9]{4})*+)*+"

scala> r.pattern.matcher("\"" + "\\ns" * 2500 + "\"").lookingAt
res4: Boolean = true

scala> r.pattern.matcher("\"" + "s" * 2500 + "\"").lookingAt
res5: Boolean = true

更新:向 scala 人员提交了一个拉取请求。它被接受了。

于 2013-10-07T20:29:25.113 回答