2013-10-07 4 views
8

Dans les combinateurs analyseur de Scala (JavaTokensParser en particulier), il y a une définition stringLiteral qui correspond à une chaîne de type Java.Regex pour correspondre String Java

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

Malheureusement, cette regex does not work for long strings. Est-ce que quelqu'un est au courant d'une implémentation réutilisable ou d'une modification de l'expression rationnelle plus économe en espace?

Répondre

3

Problème intéressant !!

Juste joué avec cela, et est venu avec les éléments suivants:

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

Note: l'expression rationnelle ci-dessus a été fixé de la première version ... à la fois le premier « \ » et les caractères de fin doivent être répété, pas seulement les caractères finaux comme je l'avais à l'origine!

Editer: Trouvé une expression régulière plus efficace. En utilisant ce qui suit, il peut analyser une chaîne de jusqu'à 950 paires \\ns, par opposition à l'original qui ne pouvait analyser que 556, au moins dans ma configuration par défaut.

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

Edit 2: Basé sur le commentaire de @schmmd, j'ai une expression régulière encore mieux. Celui-ci peut analyser le cas de torture 2500 \ns. Le secret est d'utiliser le modificateur possessive avide, cela annule fondamentalement le besoin de revenir en arrière, et donc aussi éteint la récursivité.

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

L'essence de la solution est d'essayer de mâcher autant que vous le pouvez chaque fois que vous faites correspondre quelque chose.

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 

Mise à jour: Unpull request a été présenté aux gens de scala. Et c'était accepté.

+1

Je souhaite que Java ait une implémentation regex intégrée qui utilise les NFA de Thompson ... – schmmd

+0

Votre regex va bien, mais il est logique pour moi d'enlever toutes les disjonctions. Il déborde toujours sur votre '' \\ ns "* 2500' cependant. '(" \ "" + "" "([^" \ p {Cntrl} \\] * (?: \\ [\\ '"bfnrt]) * (?: \\ u [a-fA-F0- 9] {4}) *) * "" "+" \ ""). R'. – schmmd

+0

Passer toutes mes étoiles Kleene à des étoiles Kleene possessive offre une meilleure performance. ("\" "+" "" ([^ "\ p {Cntrl} \\] * + (?: \\ [\\ '" bfnrt]) * + (?: \\ u [a-fA-F0 -9] {4}) * +) * + "" "+" \ ""). R – schmmd