【问题标题】:Java Pattern.compile ignoring escaped double quotes (\")Java Pattern.compile 忽略转义的双引号 (\")
【发布时间】:2015-07-08 12:44:13
【问题描述】:

我很难找出忽略转义引号的模式。 我想要这个:

    "10\" 2 Topping Pizza, Pasta, or Sandwich for $5 each. Valid until 2pm. Carryout only.","blah blah" 

匹配为:

   1> "10\" 2 Topping Pizza, Pasta, or Sandwich for $5 each. Valid until 2pm. Carryout only."
   2> "blah blah" 

我一直在尝试这个:

    Pattern pattern = Pattern.compile("\"[^\"]*\"");
    Matcher matcher = pattern.matcher(filteredCoupons);

我明白了

   1> "10\"
   2> "," 

【问题讨论】:

    标签: java regex escaping quotes


    【解决方案1】:

    您正在寻找的正则表达式是

    "[^"\\]*(?:\\.[^"\\]*)*"
    

    demo

    在 Java 中,

    String pattern = "\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"";
    

    【讨论】:

    • 我可以在 7 分钟内接受这个答案。我会做的。因为它工作得很好。
    • 请注意,Pshemo 的答案实际上是相同的,但包含在一个交替组中。我的“展开”版本更快更安全,因为涉及的回溯步骤更少。
    • 我不确定在这种情况下,诸如 regex101 之类的计步器有多可靠。目前没有安装 pcretest,但性能似乎很好,还没有看到这种方法。
    • 我在regexhero.net 测试了类似的正则表达式模式。虽然它是为 .NET 风格量身定制的,但我认为底层的基本机制是相似的:回溯越少,模式就越安全。
    【解决方案2】:

    您的正则表达式似乎需要接受非引号,或前面有 \ 的引号。在这种情况下尝试使用

    Pattern pattern = Pattern.compile("\"(\\\\.|[^\"])*\"");
    

    这部分正则表达式\\\\.|[^\"]会尝试查找

    • \. - 任何转义字符,
    • | 或)[^\"] - 任何非引号字符

    我将\. 放在[^\"] 之前,以防止\[^\"] 匹配。

    换句话说,对于像foo\"bar" 和正则表达式\\\\.|[^\"] 这样的文本,你会得到这个匹配

    foo\"bar"
    ^^^-matched by [^\"]
    
    foo\"bar"
       ^^-matched by \.
    
    foo\"bar"
         ^^^-matched by [^\"]
    
    foo\"bar"
            ^-can't be matched by anything since there is no \ before
              nor it is non-quote
    

    演示:

    String filteredCoupons = "\"10\\\" 2 Topping Pizza, Pasta, or Sandwich for $5 each. Valid until 2pm. Carryout only.\",\"blah blah\"";
    Pattern pattern = Pattern.compile("\"(\\\\.|[^\"])*\"");
    Matcher matcher = pattern.matcher(filteredCoupons);
    while(matcher.find()){
        System.out.println(matcher.group());
    }
    

    输出:

    "10\" 2 Topping Pizza, Pasta, or Sandwich for $5 each. Valid until 2pm. Carryout only."
    "blah blah"
    

    【讨论】:

      【解决方案3】:

      也可以使用否定的lookbehind

      (?s)".*?"(?<!\\.)
      

      作为 Java 字符串:

      "(?s)\".*?\"(?<!\\\\.)"
      

      test at regex101; test at regexplanet(点击“Java”)

      • 遇到" 后,如果没有前面的反斜杠跳过一个字符,它会向后看
      • 类似".*?(?&lt;!\\)",但在遇到" 后表现更好
      • 使用(?s) 标志使点也匹配换行符

      出于兴趣,我使用regexhero.net 的示例字符串对不同版本进行了基准测试(感谢@stribizhev 提供此链接!)。不确定regex101 的计步器在这里是否准确。

      仅使用非捕获组进行基准测试。有趣的是,"(?:\\.|[^"])*" 与捕获组 "(\\.|[^"])*" 相比,性能几乎翻了一番。

      【讨论】:

        猜你喜欢
        • 2021-09-24
        • 2015-10-23
        • 1970-01-01
        • 1970-01-01
        • 2017-08-08
        • 1970-01-01
        • 2013-10-31
        • 1970-01-01
        相关资源
        最近更新 更多