web-dev-qa-db-fra.com

java.lang.StackOverflowError lors de l'utilisation d'un RegEx pour analyser de grandes chaînes

Ceci est mon Regex

((?:(?:'[^']*')|[^;])*)[;]

Il symbolise une chaîne sur des points-virgules. Par exemple,

Hello world; I am having a problem; using regex;

Le résultat est trois chaînes

Hello world
I am having a problem
using regex

Mais lorsque j'utilise une grande chaîne d'entrée, j'obtiens cette erreur

Exception in thread "main" Java.lang.StackOverflowError
at Java.util.regex.Pattern$GroupHead.match(Pattern.Java:4168)
at Java.util.regex.Pattern$Loop.match(Pattern.Java:4295)
at Java.util.regex.Pattern$GroupTail.match(Pattern.Java:4227)
at Java.util.regex.Pattern$BranchConn.match(Pattern.Java:4078)
at Java.util.regex.Pattern$CharProperty.match(Pattern.Java:3345)
at Java.util.regex.Pattern$Branch.match(Pattern.Java:4114)
at Java.util.regex.Pattern$GroupHead.match(Pattern.Java:4168)
at Java.util.regex.Pattern$Loop.match(Pattern.Java:4295)
at Java.util.regex.Pattern$GroupTail.match(Pattern.Java:4227)

Comment cela est-il causé et comment puis-je le résoudre?

35
Ali

Malheureusement, la prise en charge regex intégrée de Java a des problèmes avec les expressions régulières contenant des chemins alternatifs répétitifs (c'est-à-dire (A|B)*). Ceci est compilé en un appel récursif, ce qui entraîne une erreur StackOverflow lorsqu'il est utilisé sur une très grande chaîne.

Une solution possible consiste à réécrire votre expression régulière pour ne pas utiliser d'alternative répétitive, mais si votre objectif est de symboliser une chaîne sur des points-virgules, vous n'avez pas vraiment besoin d'une expression régulière complexe, utilisez simplement String.split () avec un simple ";" comme argument.

54
Jeen Broekstra

Si vous avez vraiment besoin d'utiliser une expression régulière qui déborde de votre pile, vous pouvez augmenter la taille de votre pile en passant quelque chose comme -Xss40m à la JVM.

16
Andrew

Il peut être utile d'ajouter un + Après le [^;], Afin d'avoir moins de répétitions.

N'y a-t-il pas aussi une construction qui dit "si l'expression régulière correspond à ce point, ne pas revenir en arrière"? Peut-être que cela est également utile. (Mise à jour: cela s'appelle quantificateurs possessifs ).

Une alternative complètement différente consiste à écrire une méthode utilitaire appelée splitQuoted(char quote, char separator, CharSequence s) qui itère explicitement sur la chaîne et se souvient si elle a vu un nombre impair de guillemets. Dans cette méthode, vous pouvez également gérer le cas où le caractère de citation pourrait devoir être non échappé lorsqu'il apparaît dans une chaîne entre guillemets.

'I'm what I am', said the fox; and he disappeared.
'I\'m what I am', said the fox; and he disappeared.
'I''m what I am', said the fox; and he disappeared.
7
Roland Illig