このパターンがコンパイルに失敗するのはなぜですか:
Pattern.compile("(?x)[ ]\\b");
エラー
ERROR Java.util.regex.PatternSyntaxException:
Illegal/unsupported escape sequence near index 8
(?x)[ ]\b
^
at Java_util_regex_Pattern$compile.call (Unknown Source)
次の同等のものは動作しますか?
Pattern.compile("(?x)\\ \\b");
Pattern.compile("[ ]\\b");
Pattern.compile(" \\b");
これはJava regexコンパイラのバグですか、何か不足していますか?視覚的ノイズを節約するため、バックスラッシュ-バックスラッシュ-スペースの代わりに冗長正規表現で[ ]
を使用したいです。 。しかし、明らかにそれらは同じではありません!
PS:この問題はバックスラッシュに関するものではありません。バックスラッシュを使用する代わりに、単一のスペース[ ]
を含む文字クラスを使用して、冗長正規表現でスペースをエスケープすることです。
どういうわけか、冗長な正規表現(?x)
と単一のスペースを含む文字クラス[ ]
の組み合わせにより、コンパイラがスローされ、Wordの境界エスケープ\b
が認識されなくなります。
Java 1.8.0_151まででテスト済み
これは、Pattern
クラスのJavaのpeekPastWhitespace()
メソッドのバグです。この問題全体をたどって...私は OpenJDK 8-b132のPattern
実装 を調べることにしました。これを上から叩き始めましょう:
compile()
は1696行でexpr()
を呼び出しますexpr()
は1996年にsequence()
を呼び出しますsequence()
は、[
のケースが満たされたため、2063行でclazz()
を呼び出しますclazz()
は2509行目でpeek()
を呼び出しますpeek()
は、peekPastWhitespace()
がtrue
に評価されるため(パターンの先頭にx
フラグ(?x)
を追加したため、1830行でif(has(COMMENTS))
を呼び出します。 )peekPastWhitespace()
(以下に投稿)パターン内のallスペースをスキップします。private int peekPastWhitespace(int ch) {
while (ASCII.isSpace(ch) || ch == '#') {
while (ASCII.isSpace(ch))
ch = temp[++cursor]
if (ch == '#') {
ch = peekPastLine();
}
}
return ch;
}
parsePastWhitespace()
メソッドにも同じバグが存在します。
Javaの文字クラスでは[]\\b
がサポートされていないため、正規表現は\b
として解釈されていますが、これがエラーの原因です。さらに、\b
の問題を修正すると、キャラクタークラスには終了]
もありません。
この問題を解決するためにできること:
\\
OPが述べたように、単純に二重のバックスラッシュとスペースを使用します[\\ ]
文字クラス内のスペースをエスケープして、文字どおりに解釈されるようにします[ ](?x)\\b
文字クラスの後にインライン修飾子を配置します視覚的なノイズを節約するため、バックスラッシュ-バックスラッシュ-スペースの代わりに冗長正規表現で_
[ ]
_を使用するのが好きです。しかし、明らかにそれらは同じではありません!
_"[ ]"
_は_"\\ "
_または_" "
_と同じです。
問題は、コメントモードを有効にする最初の_(?x)
_です。 ドキュメント 状態として
パターン内の空白とコメントを許可します。
このモードでは、空白は無視され、_#
_で始まる埋め込みコメントは行末まで無視されます。
コメントモードは、埋め込みフラグ式_(?x)
_を使用して有効にすることもできます。
コメントモードでは、正規表現"(?x)[ ]\\b"
は_"[]\\b"
_と同じであり、空の文字クラス_[]
_は空として解析されず、_"[\\]"
_のように解析されるため、コンパイルされません。 (リテラル_]
_を含む閉じられていない文字クラス)。
代わりに_" \\b"
_を使用してください。または、バックスラッシュでエスケープすることにより、コメントモードでスペースを保持します:"(?x)[\\ ]\\b"
または"(?x)\\ \\b"
。
free-spacing(verbose)mode (?x)
[ ]
のスペースは無視されるため、正規表現エンジンは正規表現を[]\\b
として認識します。\\b
を削除すると、[]
のように表示され、Unclosed character class
に関するエラーが発生します-文字クラスを空にできないため、]
を直接配置します[
の後は、文字クラスを閉じるメタシンボルではなく、そのクラスに属する最初の文字として扱われます。
したがって、[
は閉じられていないため、正規表現エンジンは\b
が配置されていると見なしますinsideその文字クラス。ただし、\b
はそこに配置できないため(文字ではなく「場所」を表します)、「サポートされていないエスケープシーケンス」(文字クラス内でその部分はスキップされました)に関するエラーが表示されます。
言い換えると、[ ]
を使用して冗長モード(少なくともJava)でスペースをエスケープすることはできません。 "\\ "
または"[\\ ]"
を使用する必要があります。
[ ]
と文字通り同じである空白を個別にエスケープすることに加えて、正規表現全体でx
モードをオンにできますが、空白を必要とするパターンでの作業中は無効にできます。
(?x)match-this-(?-x: with spaces )\\b
^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^
`x` is on off on
または、代わりにqoutingメタ文字\Q...\E
を使用します。
(?x)match-this-\Q with s p a c e s \E\\b
^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^
`x` is on off on
Exception
なのか?拡張モードまたはコメントモード(x
)では、空白は無視されますが、さまざまなフレーバーの文字クラス内のスペースの処理方法は異なります。
たとえば、PCREでは、文字クラスの文字を除くすべての空白文字は無視されます。つまり、[ ]
は有効な正規表現ですが、Javaには例外がありません。
このモードでは、空白は無視されます...
限目。したがって、この[ ]
はこの[]
と等しく、無効であり、PatternSyntaxException
例外をスローします。
JavaScriptを除くほとんどすべての正規表現フレーバーは、少なくとも1つのデータユニットを持つ文字クラスを必要とします。空の文字クラスは、閉じ括弧が必要な閉じられていないセットとして扱われます。 []]
はほとんどのフレーバーで有効です。
[ ]
の異なるフレーバーのフリースペースモード:
PCRE
有効.NET
有効Perl
有効Ruby
有効TCL
有効Java 7
無効Java 8
無効何が起こるかを正確に分析しましょう。
Java.util.regex.Pattern のソースコードを見てください
パターン内の空白とコメントを許可します。 このモードでは、空白は無視され、#で始まる埋め込みコメントは行末まで無視されます。
コメントモードは、埋め込みフラグ式(?x)でも有効にできます。
あなたの正規表現はあなたにこれを案内します line
private void accept(int ch, String s) {
int testChar = temp[cursor++];
if (has(COMMENTS))
testChar = parsePastWhitespace(testChar);
if (ch != testChar) {
throw error(s);
}
}
コード呼び出しに気付いた場合 parsePastWhitespace(testChar);
private int parsePastWhitespace(int ch) {
while (ASCII.isSpace(ch) || ch == '#') {
while (ASCII.isSpace(ch))//<----------------Here is the key of your error
ch = temp[cursor++];
if (ch == '#')
ch = parsePastLine();
}
return ch;
}
あなたの場合、正規表現に空白があります(?x)[ ]\\b
これは何かを返します(正しく分析できません):
if (ch != testChar) {
throw error(s);
}
ch
と等しくない場合、ここで例外がスローされます
throw error(s);