2013-10-07 4 views
8

В компиляторах синтаксического анализатора Scala (JavaTokensParser) есть определение stringLiteral, которое соответствует строке, подобной Java.Regex соответствует Java String

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

К сожалению, это регулярное выражение does not work for long strings. Кто-нибудь знает о повторно используемой реализации, которая делает, или изменение в регулярном выражении, которое более эффективно с точки зрения пространства?

ответ

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 

Edit 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 

Update:pull request был представлен на SCALA людей. И это было принято.

+1

Я хочу, чтобы Java имела встроенную реализацию регулярных выражений, которая использовала Noms Thompson ... – schmmd

+0

Ваше регулярное выражение в порядке, но имеет смысл для меня удалить все дизъюнкции. Однако он все равно переполняется на '' \\ ns * * 2500'. '(" \ "" + "" "([^" \ p {Cntrl} \\] * (?: \\ [\\ '"bfnrt]) * (?: \\ u [a-fA-F0- 9] {4}) *) * "" "+" \ ""). R'. – schmmd

+0

Переключение всех моих звезд Kleene на притяжательные звезды Kleene обеспечивает лучшую производительность. ("\" "+" "" ([^ "\ p {Cntrl} \\] * + (?: \\ [\\ '" bfnrt]) * + (?: \\ u [a-fA-F0 -9] {4}) * +) * + "" "+" \ ""). R – schmmd

Смежные вопросы