129

我正在尝试将 theString \something\转换为String \\something\\using replaceAll,但我不断收到各种错误。我认为这是解决方案:

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

但这给出了以下例外:

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

5 回答 5

222

String#replaceAll()参数解释为正则表达式。在和中都是\转义字符。您需要对正则表达式进行双重转义: Stringregex

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

但是你不一定需要正则表达式,只是因为你想要一个精确的逐个字符替换并且你不需要这里的模式。所以String#replace()应该足够了:

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

更新:根据评论,您似乎想在 JavaScript 上下文中使用该字符串。你也许最好用它StringEscapeUtils#escapeEcmaScript()来覆盖更多的字符。

于 2009-11-09T15:45:49.197 回答
15

TLDR:theString = theString.replace("\\", "\\\\");改用。


问题

replaceAll(target, replacement)target对和部分使用正则表达式 (regex) 语法replacement

问题是\正则表达式中的特殊字符(它可以用来\d表示数字)和字符串文字(它可以用来"\n"表示行分隔符或\"转义通常表示字符串结尾的双引号)。

在这两种情况下,为了创建\符号,我们可以通过在它之前放置附加来对其进行转义(使其成为文字而不是特殊字符)\(就像我们"在字符串文字中通过转义一样\")。

因此,target表示\符号的正则表达式需要保持\\,而表示此类文本的字符串文字需要看起来像"\\\\"

所以我们逃了\两次:

  • 一次在正则表达式中\\
  • 一次在字符串文字中"\\\\"(每个\都表示为"\\")。

万一replacement \也特别有。$它允许我们通过符号转义其他特殊字符$x,允许我们使用由正则表达式匹配并由索引为的捕获组保存的部分数据x,例如"012".replaceAll("(\\d)", "$1$1")将匹配每个数字,将其放入捕获组 1 并将$1$1其替换为它的两个副本(它会复制它)导致"001122".

再说一次,要让replacement表示\文字,我们需要用附加来转义它,\这意味着:

  • 替换必须包含两个反斜杠字符\\
  • 和表示\\看起来像的字符串文字"\\\\"

但是因为我们想要replacement保留两个反斜杠,所以我们需要"\\\\\\\\"(每个都\用一个表示"\\\\")。

所以版本replaceAll看起来像

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

更简单的方法

为了让生活更轻松,Java 提供了自动将文本转义为targetreplacement部分的工具。所以现在我们可以只关注字符串,而忘记正则表达式的语法:

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

在我们的例子中看起来像

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

甚至更好

如果我们真的不需要正则表达式语法支持,那就根本不参与replaceAll。相反,让我们使用replace. 两种方法都将替换所有 targets,但replace不涉及正则表达式语法。所以你可以简单地写

theString = theString.replace("\\", "\\\\");
于 2016-10-20T20:39:28.377 回答
14

为避免此类麻烦,您可以使用replace(采用纯字符串)而不是replaceAll(采用正则表达式)。您仍然需要转义反斜杠,但不需要以正则表达式所需的狂野方式。

于 2009-11-09T15:45:25.547 回答
7

您需要转义第一个参数中的(转义)反斜杠,因为它是正则表达式。替换(第二个参数 - 请参阅Matcher#replaceAll(String))也具有反斜杠的特殊含义,因此您必须将它们替换为:

theString.replaceAll("\\\\", "\\\\\\\\");
于 2009-11-09T15:43:48.220 回答
3

是的......当正则表达式编译器看到你给它的模式时,它只看到一个反斜杠(因为Java的词法分析器已经把双反斜杠变成了一个反斜杠)。你需要用 替换"\\\\""\\\\"信不信由你!Java 确实需要良好的原始字符串语法。

于 2009-11-09T15:44:35.993 回答