【问题标题】:String replace throws error with $ sign字符串替换用 $ 符号抛出错误
【发布时间】:2013-04-15 15:17:03
【问题描述】:

我在替换 java 中的字符串时遇到问题...

该行是:

subject = subject.replaceAll("\\[calEvent\\]", calSubject);

此行不适用于 $ 登录 calSubject。

主题变量是什么,来自文件的动态主题行变量。例如像这样: Calnot = [calEvent]

我想要做的是用主题变量替换 calEvent 占位符。但是我是怎么做的却不起作用,因为当主题包含 $ 符号时它会崩溃。

知道如何做到这一点,以便在主题包含 $ 符号或任何字符时不会中断吗?

【问题讨论】:

  • 当你说它崩溃时,你是什么意思?你有堆栈跟踪还是根本没有替换任何东西?
  • 您是否遇到了 IllegalArgumentException?
  • 错误是:java.lang.IndexOutOfBoundsException: No group 3
  • @OakvilleWork 这是合乎逻辑的,如果它将美元符号解释为捕获组引用,它会尝试用相应的组替换它,如果没有这样的组,它会抛出一个 out-of-绑定异常。

标签: java regex string


【解决方案1】:

那是因为美元符号是替换字符串中的特殊字符,使用Matcher.quoteReplacement()转义这种字符。

subject = subject.replaceAll("\\[calEvent\\]", Matcher.quoteReplacement(calSubject));

来自String.replaceAll() 的文档:

注意替换中的反斜杠 (\) 和美元符号 ($) 字符串可能会导致结果与之前的结果不同 视为文字替换字符串;请参阅 Matcher.replaceAll。利用 Matcher.quoteReplacement(java.lang.String)压制特殊 如果需要,这些字符的含义。

请注意,美元符号用于指代正则表达式中对应的捕获组($0$1 等)。

编辑

Matcher.quoteReplacement() 已在 Java 1.5 中引入,如果您在 Java 1.4 中遇到问题,则必须手动转义 $,方法是在字符串中将其替换为 \$。但是由于String.replaceAll() 也会将\$ 作为特殊字符,因此您必须将它们转义一次,并且您还必须为Java 运行时再次转义所有\

("$", "\$") /* what we want */
("\$", "\\\$") /* RegExp engine escape */
("\\$", "\\\\\\$") /* Java runtime escape */

所以我们得到:

calSubject = calSubject.replaceAll("\\$", "\\\\\\$");  

【讨论】:

  • 您好,非常感谢您的建议。该程序使用 java 1.4,但似乎无法正常工作。很难说,因为我无法在本地调试它。只是使用日志来解决它。 java 1.4 不支持:Matcher.quoteReplacement?
  • java regex 文档中是否有提到使用美元符号来指代捕获组?
  • 是的,在 Matcher#replaceAll 的 Javadoc 中:Dollar signs may be treated as references to captured subsequences
【解决方案2】:

如果你不需要regex的特性,你可以考虑使用String类的这个方法: replace(CharSequence target,CharSequence replacement)

它还可以保存您的“转义”反斜杠。

api 文档:

替换此字符串中与 文字目标匹配的每个子字符串 具有指定文字替换序列的序列。这 替换从字符串的开头到结尾进行,对于 例如,将字符串“aaa”中的“aa”替换为“b”将导致 “ba”而不是“ab”。

【讨论】:

  • 你能举个例子吗?
  • 在 JDK 1.5 中添加了 replace() 方法的重载,并且 OP 被 JDK 1.4 卡住了。而且您不能使用replace(char, char),因为新值不是单个char
  • @AlanMoore 在我发帖时,OP 没有提到任何关于 1.4 的信息。但你是对的,这个方法是从 1.5 开始的。
【解决方案3】:

来自replaceAll的文档:

注意替换中的反斜杠 () 和美元符号 ($) 字符串可能会导致结果与之前的结果不同 视为文字替换字符串;请参阅 Matcher.replaceAll。利用 java.util.regex.Matcher.quoteReplacement 抑制特殊 如果需要,这些字符的含义。

在 Matcher.replaceAll 中

美元符号可以被视为对捕获的子序列的引用 如上所述,反斜杠用于转义文字字符 在替换字符串中。

【讨论】:

    【解决方案4】:

    不确定我是否真的理解您的问题,但请尝试

    subject = subject.replaceAll("\\[calEvent\\]", Matcher.quoteReplacement(calSubject));
    

    【讨论】:

      【解决方案5】:

      请使用

      Matcher.quoteReplacement(calEvent);
      

      【讨论】: