web-dev-qa-db-ja.com

String.replaceすべての単一のバックスラッシュと二重のバックスラッシュ

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

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

ただし、これには以下の例外があります。

Java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
110

String#replaceAll() は、引数を 正規表現 として解釈します。 \は、bothStringおよびregexのエスケープ文字です。あなたは正規表現のためにそれを二重エスケープする必要があります:

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

ただし、正確な文字ごとの置換が必要であり、ここでパターンが必要ないという理由だけで、必ずしも正規表現は必要ありません。 String#replace() で十分です:

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

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

189
BalusC

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

14
Fabian Steeg

TLDR:代わりにtheString = theString.replace("\\", "\\\\");を使用します。


問題

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

問題は、\が正規表現(数字を表す\dのように使用できる)および文字列リテラル(行区切りを表す"\n"のような特殊文字であるか、または通常文字列リテラルの終わりを表す二重引用符をエスケープする\"であるということです)。

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

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

そこで、\を2回エスケープしました。

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

replacementの場合、\も特別です。他の特殊文字$をエスケープして、$x表記を使用して、正規表現に一致し、"012".replaceAll("(\\d)", "$1$1")が各桁に一致するなど、xとしてインデックス付けされたグループをキャプチャすることで保持されるデータの一部を使用できるようにしますグループ1をキャプチャすると、$1$1は2つのコピーに置き換えられ(複製されます)、"001122"になります。

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

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

ただし、replacementtwoバックスラッシュを保持する必要があるため、"\\\\\\\\"(1つの\で表される各"\\\\")が必要になります。

したがって、replaceAllを含むバージョンは次のようになります。

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

より簡単な方法

生活を楽にするために、Javaは、テキストをtargetおよびreplacement部分に自動的にエスケープするツールを提供します。そのため、文字列のみに注目し、正規表現の構文を忘れることができます。

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

この場合、次のようになります

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

さらに良い

正規表現の構文サポートが本当に必要ない場合は、replaceAllをまったく含めないでください。代わりにreplaceを使用してください。両方のメソッドがalltargetsを置き換えますが、replaceは正規表現構文を含みません。だからあなたは単に書くことができます

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

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

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

はい...正規表現コンパイラが指定されたパターンを見るまでに、バックスラッシュは1つだけ表示されます(Javaのレクサーがダブルバックワックを1つに変えたため)。 "\\\\""\\\\"に置き換える必要があります。信じられないかもしれません! Javaには、適切な生の文字列構文が本当に必要です。

4