String.replaceすべての単一の円記号と二重の円記号


122

をusing に変換しようとしていますString \something\が、あらゆる種類のエラーが発生し続けます。これが解決策だと思いました:String \\something\\replaceAll

theString.replaceAll("\\", "\\\\");

しかし、これは以下の例外を与えます:

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1

回答:


204

String#replaceAll()引数を解釈する正規表現を\でエスケープ文字で両方 Stringregex。あなたは正規表現のためにそれをダブルエスケープする必要があります:

string.replaceAll("\\\\", "\\\\\\\\");

しかし、これは必ずしも正規表現を必要としません。正確な文字ごとの置換が必要であり、ここでパターンを必要としないからです。それでString#replace()十分です:

string.replace("\\", "\\\\");

更新:コメントに従って、JavaScriptコンテキストで文字列を使用したいようです。StringEscapeUtils#escapeEcmaScript()代わりに、より多くのキャラクターをカバーするために使用する方がよいでしょう。


実際には、ソースに変換し直す必要があるJavaScript ASTで使用されます。あなたのソリューションは機能します。ありがとう!
フランクGroeneveld

2
あなたが使用したい場合はString#replaceAll()、とにかく、あなたはとの置換文字列を引用できるのMatcher#quoteReplacement() theString.replaceAll("\\", Matcher.quoteReplacement("\\\\"));
phse

Matcher.quoteReplacement(...)は良い方法です!Pshemoの回答をご覧ください。
Hartmut P.

14

この種の問題を回避するreplaceには、replaceAll(正規表現を使用する)の代わりに(プレーンな文字列を使用する)を使用できます。引き続きバックスラッシュをエスケープする必要がありますが、正規表現で必要とされるワイルドな方法ではありません。


10

TLDR:theString = theString.replace("\\", "\\\\");代わりに使用してください。


問題

replaceAll(target, replacement)では正規表現(regex)構文をtarget部分的に使用していreplacementます。

問題は\、正規表現(\d数字を表すのに使用できる)や文字列リテラル(通常、文字列リテラルの終わり"\n"を表す行区切り文字や\"二重引用符をエスケープするのに使用できる)の特殊文字です。

これらのどちらの場合でも、\シンボルを作成するために、その前に追加を配置することで(特殊文字の代わりにリテラルにする)シンボルをエスケープできます\"文字列リテラルでを介してエスケープするように\")。

したがって、シンボルをtarget表す正規表現は\保持する必要があり\\、そのようなテキストを表す文字列リテラルは次のようにする必要があります"\\\\"

したがって、\2回エスケープしました。

  • 正規表現で一度 \\
  • 文字列リテラルで1回"\\\\"(それぞれ\として表されます"\\")。

replacement \特別な場合もございます。それは、私たちは、他の特殊文字エスケープすることができます$経由で$xの表記、私たちは、データの一部が正規表現にマッチしたとしてインデックス付けキャプチャグループが保有する使用することができますxように、"012".replaceAll("(\\d)", "$1$1")グループ1の捕捉に各桁と一致します、場所、それをし、$1$1その2回のコピーと交換します(それは複製されます)結果はになり"001122"ます。

繰り返しますが、リテラルをreplacement表す\には、追加\でエスケープする必要があります。つまり、

  • 置換には2つのバックスラッシュ文字を含める必要があります \\
  • 表し、文字列リテラル\\のようなルックスを"\\\\"

しかし、必要な2つのバックスラッシュをreplacement保持したいので(それぞれ1で表されます)。"\\\\\\\\"\"\\\\"

のバージョンreplaceAllは次のようになります

replaceAll("\\\\", "\\\\\\\\");

より簡単な方法

人生は簡単にアウトにするためにJavaは自動的にテキストをエスケープするためのツールを提供targetし、replacement部品を。これで、文字列のみに焦点を当てることができ、正規表現の構文を忘れることができます。

replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))

私たちの場合は次のようになります

replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))

さらに良い

正規表現構文のサポートが本当に必要ない場合はreplaceAll、一切関与させません。代わりにを使用できますreplace。どちらの方法でもすべて targetのが置き換えられますreplace、正規表現構文は含まれません。だからあなたは単に書くことができます

theString = theString.replace("\\", "\\\\");

7

これは正規表現なので、最初の引数で(エスケープされた)バックスラッシュをエスケープする必要があります。置換(2番目の引数-Matcher#replaceAll(String)を参照)にもバックスラッシュの特別な意味があるため、これらを次のように置き換える必要があります。

theString.replaceAll("\\\\", "\\\\\\\\");

3

はい...正規表現コンパイラが指定したパターンを認識するまでに、バックスラッシュは1つしか見えません(Javaのレクサーが2つのバックスラックを1つに変換したため)。あなたは交換する必要がある"\\\\""\\\\"、それを信じるかどうか!Javaは本当に良い生の文字列構文を必要とします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.