在Scala的解析器组合器中(特别是JavaTokensParser),有一个与类似Java的字符串匹配的定义stringLiteral。
def stringLiteral: Parser[String] =
("\""+"""([^"\p{Cntrl}\\]|\\[\\'"bfnrt]|\\u[a-fA-F0-9]{4})*"""+"\"").r
不幸的是,这个正则表达式does not work for long strings。有没有人知道一个可重用的实现,或者对正则表达式的修改是否更节省空间?
答案 0 :(得分: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人员提交了pull request。它被接受了。