什么时候'。'在正则表达式中不匹配?

时间:2013-04-22 14:55:46

标签: java regex

我遇到了以下问题(简化)。我写了以下

Pattern pattern = Pattern.compile("Fig.*");
String s = readMyString();
Matcher matcher = pattern.matcher(s);

在读取一个字符串时,匹配器无法匹配,即使它以“图”开头。我将问题跟踪到字符串下一部分中的流氓角色。它的代码点值为1633来自

(int) charAt(i)

但与正则表达式不匹配。我认为这是由于输入过程中某处出现了非UTF-8编码。

Javadocs说:

  

预定义的字符类   。任何字符(可能与行终止符匹配也可能不匹配)

据推测,这不是严格意义上的字符,但仍然是字符串的一部分。我如何检测到这个问题?

更新:这是由于(char)10不容易发现。我上面的诊断是错误的,下面的所有答案都与所提出的问题相关并且很有用。

4 个答案:

答案 0 :(得分:13)

检查这个很容易:

import java.util.regex.*;

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile(".");
        for (char c = 0; c < 0xffff; c++) {
            String text = String.valueOf(c);
            if (!pattern.matcher(text).matches()) {
                System.out.println((int) c);
            }
        }
    }
}

在我的方框中,输出为:

10
13
133
8232
8233

其中,10和13分别是“\ n”和“\ r”。 133(U + 0085)是“下一行”,8232(U + 2028)是“行分隔符”,8233(U + 2029)是“段落分隔符”。

请注意:

  • 这不会测试基本多语言平面之外的任何Unicode字符
  • 仅使用默认选项
  • 这似乎与你对1633(U + 0661)
  • 的经历相矛盾

答案 1 :(得分:11)

Java正则表达式中的.字符匹配除行终止符之外的任何字符,除非在编译模式时使用标记Pattern.DOTALL

为此,您可以使用这样的模式:

Pattern p = Pattern.compile("somepattern", Pattern.DOTALL);

答案 2 :(得分:2)

根据documentation.可以有 3略有不同的解释,具体取决于标记。

默认

禁用line terminators模式和DOTALL模式时,

.会排除UNIX_LINES(默认):

  

行结束符是一个单字符或双字符序列,用于标记输入字符序列行的结尾。以下被认为是行终止符:

     
      
  • 换行符(换行符)('\n'),
  •   
  • 回车符后面紧跟换行符("\r\n"),
  •   
  • 一个独立的回车符('\r'),
  •   
  • 下一行字符('\u0085'),
  •   
  • 行分隔符('\u2028')或
  •   
  • 段落分隔符('\u2029')。
  •   

这意味着.在这种情况下相当于[^\n\r\u0085\u2028\u2029]

启用UNIX_LINES模式但禁用DOTALL模式

启用UNIX_LINES模式后,

.将仅排除 \n,但会禁用DOTALL模式。这意味着.在这种情况下相当于[^\n]

  

如果激活UNIX_LINES模式,则识别的唯一行终止符是换行符。

启用DOTALL模式时

如果启用了DOTALL模式,.将匹配任何字符,无例外

  

正则表达式.匹配除行终止符之外的任何字符,除非指定了DOTALL标志。

答案 3 :(得分:1)

关于使用正则表达式非打印字符,您可以阅读以下两篇文章:

  1. How to match nonprintable characters with a regular expression
  2. How to use Unicode code points, properties, blocks, and scripts in regular expressions
  3. 即使您完全使用UTF,也会有很多惊喜。