これは私の正規表現です
((?:(?:'[^']*')|[^;])*)[;]
セミコロンの文字列をトークン化します。例えば、
Hello world; I am having a problem; using regex;
結果は3つの文字列です
Hello world
I am having a problem
using regex
しかし、大きな入力文字列を使用すると、このエラーが発生します
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)
これはどのように引き起こされ、どのように解決できますか?
残念ながら、Javaの組み込み正規表現サポートには、反復的な代替パス(つまり、(A|B)*
)を含む正規表現で問題があります。これは再帰呼び出しにコンパイルされるため、非常に大きな文字列で使用するとStackOverflowエラーが発生します。
可能な解決策は、正規表現を書き直して代替表現を使用しないことですが、セミコロンで文字列をトークン化することを目標とする場合は、実際には複雑な正規表現は必要ありません。 String.split()を使用するだけです。 引数として単純な";"
を使用します。
スタックをオーバーフローする正規表現を本当に使用する必要がある場合は、-Xss40mのようなものをJVMに渡すことにより、スタックのサイズを増やすことができます。
繰り返しが少なくなるように、_+
_の後に_[^;]
_を追加すると役立つ場合があります。
「正規表現がこの時点まで一致した場合、バックトレースしないでください」という構造もありませんか?多分それも重宝します。 (更新: 所持量指定子 と呼ばれます))。
まったく異なる代替手段は、splitQuoted(char quote, char separator, CharSequence s)
と呼ばれるユーティリティメソッドを記述して、文字列を明示的に反復し、奇数の引用符が見られたかどうかを記憶することです。その方法では、引用符付き文字列に引用符文字が含まれている場合、引用符文字をエスケープ解除する必要がある場合にも対処できます。
_'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.
_