【问题标题】:Do I always need to escape metacharacters in a string that is not a "literal"?我是否总是需要转义不是“文字”的字符串中的元字符?
【发布时间】:2015-10-30 20:08:40
【问题描述】:

在正则表达式处理期间,似乎有一个包含字符 {} 的字符串被拒绝。我可以理解这些是保留字符,我需要转义它们,所以如果我这样做:

string.replaceAll("\\" + pattern);

这可行,其中pattern 是任何以{ 开头的字符串。

问题:有没有办法避免已经包含此类元字符的字符串出现此类问题,以便自动处理?在我看来,它应该与在字符串文字中添加双引号与接受已经具有双引号的字符串作为输入相同

【问题讨论】:

  • 使用replace 而不是replaceAll
  • @Pshemo:他们的行为不同?
  • 阅读文档...replace(char, char)replace(String, String) 都应该适合你。
  • 如果任何答案对您有所帮助,请接受它以指出正确的解决方案!

标签: java regex string


【解决方案1】:

使用Pattern.quote(String):

public static String quote(String s)

为指定的String 返回文字模式String

此方法生成一个String,可用于创建一个Pattern,该Pattern 将匹配字符串s,就好像它是一个文字模式一样。

输入序列中的元字符或转义序列不会被赋予特殊含义。

参数:
s - 要字面化的字符串
返回:
文字字符串替换
自:
1.5

【讨论】:

    【解决方案2】:

    你可以使用

    java.util.regex.Pattern.quote(java.lang.String)
    

    转义正则表达式使用的元字符。

    【讨论】:

      【解决方案3】:

      TL;DR

      • 如果您需要正则表达式语法,请使用replaceAllreplaceFirst
      • 如果您希望您的 target/replacement 对被视为文字,请使用 replace(它还替换 所有 次出现的目标)。

      大多数人对 String 类中替换方法的不幸命名感到困惑:

      • replaceAll(String, String)
      • replaceFirst(String, String)
      • replace(CharSequence, CharSequence)
      • replace(char, char)

      由于replaceAll 方法明确声称它替换了所有 可能的目标,人们认为replace 方法不保证这种行为,因为它不包含All 后缀.
      但这个假设是错误的。

      这些方法之间的主要区别如下表所示:

      ╔═════════════════════╦═══════════════════════════════════════════════════════════════════╗
      ║                     ║                             replaced targets                      ║
      ║                     ╠════════════════════════════════════╦══════════════════════════════╣
      ║                     ║           ALL found                ║      ONLY FIRST found        ║
      ╠══════╦══════════════╬════════════════════════════════════╬══════════════════════════════╣
      ║      ║   supported  ║ replaceAll(String, String)         ║ replaceFirst(String, String) ║
      ║regex ╠══════════════╬════════════════════════════════════╬══════════════════════════════╣
      ║syntax║      not     ║ replace(CharSequence, CharSequence)║              \/              ║
      ║      ║   supported  ║ replace(char, char)                ║              /\              ║
      ╚══════╩══════════════╩════════════════════════════════════╩══════════════════════════════╝
      

      现在,如果您不需要使用 regex 语法使用方法,它并不期望它,但它会将 targetreplacement 视为文字。

      所以不是replaceAll(regex, replacement)

      使用replace(literal, replacement)


      如您所见,replace 有两个重载版本。它们都应该为您工作,因为它们不支持正则表达式语法。它们之间的主要区别在于:

      • replace(char target, char replacement) 只需创建新字符串并用原始字符串中的字符或您决定替换的字符(取决于它是否等于目标字符)填充它

      • replace(CharSequence target, CharSequence replacement) 本质上等同于 replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement.toString()) 这意味着它与replaceAll 相同,但(这意味着它在内部使用正则表达式引擎)但它会自动为我们转义targetreplacement 中使用的正则表达式元字符

      【讨论】:

      【解决方案4】:

      您不需要任何额外的代码,只需要 \Q\E 构造,如 Java's Pattern class 中所述。

      例如在下面的代码中:

      String foobar = "crazyPassword=f()ob@r{}+";
      Pattern regex = Pattern.compile("\\Q" + foobar "\\E");
      

      该模式将编译并且 foobar 的特殊字符不会被解释为正则表达式字符。见演示here

      唯一不匹配的是输入包含文字\E。如果你也需要解决这个问题,请在评论中告诉我,我会编辑添加。

      【讨论】:

        猜你喜欢
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-06
        • 2011-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多