将所有单反斜杠替换为双反斜杠

我试图转换的 String \something\String \\something\\使用 replaceAll,但我不断得到各种各样的错误。我以为这就是解决办法:

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

但这给了以下例外情况:

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
170750 次浏览

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

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

是的... 当正则表达式编译器看到您给出的模式时,它只看到一个反斜杠(因为 Java 的 lexer 已经将双重反斜杠转换为单一反斜杠)。你需要用 "\\\\"代替 "\\\\",信不信由你!Java 真的需要一个好的原始字符串语法。

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

String#replaceAll()将参数解释为 正则表达式\都有Stringregex中的转义字符。对于 regex,需要双重转义:

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

但是您不一定需要正则表达式,因为您需要精确的字符替换,而且这里不需要模式。因此,String#replace()应该足够了:

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

更新 : 根据注释,您似乎希望在 JavaScript 上下文中使用该字符串。您可能最好使用 StringEscapeUtils#escapeEcmaScript()来覆盖更多的字符。

TLDR: 使用 theString = theString.replace("\\", "\\\\");代替。


问题

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

问题是,\在 regex 中是特殊字符(它可以像 \d一样用来表示数字) ,在 String Literal 中是特殊字符(它可以像 "\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。这两种方法都将替换 所有人 target,但是 replace不涉及正则表达式语法。所以你可以简单地写

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