TLDR:改用theString = theString.replace("\\", "\\\\");。
问题
replaceAll(target, replacement) 对target 和部分replacement 使用正则表达式 (regex) 语法。
问题是\是正则表达式中的特殊字符(它可以像\d一样用来表示数字)和字符串文字(它可以像"\n"一样用来表示行分隔符或\"来转义双引号符号,通常表示字符串文字的结尾)。
在这两种情况下,要创建\ 符号,我们可以转义它(使其成为文字而不是特殊字符),方法是在它之前放置额外的\(就像我们在字符串中转义"文字通过\")。
所以对于代表\ 符号的target 正则表达式将需要保存\\,并且代表此类文本的字符串文字需要看起来像"\\\\"。
所以我们两次逃脱了\:
- 一次在正则表达式
\\
- 在字符串文字
"\\\\" 中出现一次(每个\ 表示为"\\")。
replacement\ 的情况也很特殊。它允许我们转义其他特殊字符$,通过$x 表示法,允许我们使用由正则表达式匹配的部分数据,并由索引为x 的捕获组保存,例如"012".replaceAll("(\\d)", "$1$1") 将匹配每个数字,放置它在捕获组 1 中,$1$1 将用它的两个副本替换它(它会复制它)导致"001122"。
再一次,让replacement 代表\ 文字,我们需要用额外的\ 对其进行转义,这意味着:
- 替换必须包含两个反斜杠字符
\\
- 和代表
\\ 的字符串文字看起来像"\\\\"
但是由于我们希望 replacement 保留 两个 反斜杠,我们将需要 "\\\\\\\\"(每个 \ 由一个 "\\\\" 表示)。
所以replaceAll 的版本看起来像
replaceAll("\\\\", "\\\\\\\\");
更简单的方法
为了让生活更轻松,Java 提供了自动将文本转义为 target 和 replacement 部分的工具。所以现在我们可以只关注字符串,而忘掉正则表达式:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
在我们的例子中看起来像
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
更好
如果我们真的不需要正则表达式语法支持,就根本不涉及replaceAll。相反,让我们使用replace。这两种方法都将替换 all targets,但 replace 不涉及正则表达式语法。所以你可以简单地写
theString = theString.replace("\\", "\\\\");