未转义的java在regex matcher.find()中不匹配

时间:2014-04-02 21:38:49

标签: java regex

我有以下代码基本匹配“匹配这个:”并保留第一句话。但是,有时会将unicode字符传递到文本中,导致其他更复杂的正则表达式的回溯。转义似乎可以减少回溯指数超出范围异常。但是,现在正则表达式不匹配。

我想知道的是为什么这个正则表达式在转义时不匹配?如果你注释掉escape / unescape java就行了。

    String text = "Keep this\n\n"
            + "Match this:\n\nDelete  this";
    text = org.apache.commons.lang.StringEscapeUtils.escapeJava(text);
    Pattern PATTERN = Pattern.compile("^Match this:$",
            Pattern.MULTILINE);
    Matcher m = PATTERN.matcher(text);
    if (m.find()) {
        text = text.substring(0, m.start()).replaceAll("[\\n]+$", "");
    }
    text = org.apache.commons.lang.StringEscapeUtils.unescapeJava(text);
    System.out.println(text);

1 个答案:

答案 0 :(得分:3)

  

我想知道的是为什么这个正则表达式在转义时不匹配?

当你像"foo\nbar"这样的字符串被转义时,其打印类似于

foo
bar

你得到"foo\\nbar"的印刷品看起来像

foo\nbar

之所以发生这种情况,是因为StringEscapeUtils.escapeJava也会\n转义并将其替换为\\n,因此它不再是行分隔符而是简单的文字,因此无法与之匹配^$

可能的解决方案可能是在"\\n"之后用"\n"替换StringEscapeUtils.escapeJava。你需要在这里小心,而不是" unescapee"替换后的真实"\\n"会给你"\\\\n"打印的内容看起来像\\n。所以也许可以使用

text = org.apache.commons.lang3.StringEscapeUtils.escapeJava(text);
text = text.replaceAll("(?<!\\\\)\\\\n", "\n");// escape `\n` 
                                               // if it is not preceded with `\`
//do your job

//and now you can unescape your text (\n will stay \n)
text = org.apache.commons.lang3.StringEscapeUtils.unescapeJava(text);

另一种选择可能是创建类似StringEscapeUtils.escapeJava的自己的实现。如果你看一下这个方法体,你会看到

return ESCAPE_JAVA.translate(input);

ESCAPE_JAVA

的位置
CharSequenceTranslator ESCAPE_JAVA = 
  new LookupTranslator(
    new String[][] { 
      {"\"", "\\\""},
      {"\\", "\\\\"},
  }).with(
    new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE())
  ).with(
    UnicodeEscaper.outsideOf(32, 0x7f) 
);

EntityArrays.JAVA_CTRL_CHARS_ESCAPE()返回

的克隆
String[][] JAVA_CTRL_CHARS_ESCAPE = {
    {"\b", "\\b"},
    {"\n", "\\n"},
    {"\t", "\\t"},
    {"\f", "\\f"},
    {"\r", "\\r"}
};

阵列。因此,如果您在此处提供了自己的表格,该表格会明确说明\n应保留原样(因此应将其替换为自身\n),您的代码将忽略它。

这就是你自己的实现看起来像

的方式
private static CharSequenceTranslator translatorIgnoringLineSeparators = 
    new LookupTranslator(
        new String[][] { 
                { "\"", "\\\"" }, 
                { "\\", "\\\\" }, 
        }).with(
                new LookupTranslator(new String[][] {
                        { "\b", "\\b" },
                        { "\n", "\n"  },//this will handle `\n` and will not change it
                        { "\r", "\r"  },//this will handle `\r` and will not change it
                        { "\t", "\\t" }, 
                        { "\f", "\\f" },
        })).with(UnicodeEscaper.outsideOf(32, 0x7f));

public static String myJavaEscaper(CharSequence input) {
    return translatorIgnoringLineSeparators.translate(input);
}

此方法可防止转义\r\n