Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
到目前为止,我们只使用测试工具以最基本的形式创建 Pattern 对象。本节探讨高级技术,例如使用标志创建模式和使用嵌入式标志表达式。它还探讨了我们尚未讨论的一些其他有用的方法。
Pattern 类定义了一个备用 compile 方法,该方法接受一组影响模式匹配方式的标志。flags 参数是一个位掩码,可能包含以下任何公共静态字段:
Pattern.CANON_EQ启用规范等效。当指定此标志时,当且仅当两个字符的完整规范化分解匹配时,才认为这两个字符匹配。例如,当指定此标志时,表达式 "a\u030A" 将匹配字符串 "\u00E5"。默认情况下,匹配不会将规范等效考虑在内。指定此标志可能会导致性能下降。Pattern.CASE_INSENSITIVE启用不区分大小写的匹配。默认情况下,不区分大小写的匹配假定只匹配 US-ASCII 字符集中的字符。通过将 UNICODE_CASE 标志与此标志一起指定,可以启用 Unicode 感知的不区分大小写的匹配。也可以通过嵌入式标志表达式 (?i) 启用不区分大小写的匹配。指定此标志可能会略微降低性能。Pattern.COMMENTS允许模式中的空格和注释。在此模式下,将忽略空格,并忽略以 # 开头的嵌入式注释,直到行结束。也可以通过嵌入式标志表达式 (?x) 启用注释模式。Pattern.DOTALL启用 dotall 模式。在 dotall 模式下,表达式 . 匹配任何字符,包括行终止符。默认情况下,此表达式与行终止符不匹配。也可以通过嵌入式标志表达式 (?s) 启用 Dotall 模式。(s 是“单行”模式的助记符,在 Perl 中就是这样称呼的。)Pattern.LITERAL启用模式的文字解析。指定此标志后,指定模式的输入字符串将被视为文字字符序列。输入序列中的元字符或转义序列将没有特殊含义。当与此标志一起使用时,标志 CASE_INSENSITIVE 和 UNICODE_CASE 会保持对匹配的影响。其他标志变得多余。没有用于启用文字解析的嵌入标志字符。Pattern.MULTILINE启用多行模式。在多行模式下,表达式 ^ 和 $ 分别在行终止符之后或之前匹配,或者在输入序列的末尾之前匹配。默认情况下,这些表达式仅在整个输入序列的开头和结尾处匹配。也可以通过嵌入式标志表达式 (?m) 启用多行模式。Pattern.UNICODE_CASE启用支持 Unicode 的大小写折叠。指定此标志后,当由 CASE_INSENSITIVE 标志启用时,不区分大小写的匹配将以与 Unicode 标准一致的方式完成。默认情况下,不区分大小写的匹配假定只匹配 US-ASCII 字符集中的字符。也可以通过嵌入式标志表达式 (?u) 启用支持 Unicode 的大小写折叠。指定此标志可能会导致性能下降。Pattern.UNIX_LINES启用 UNIX 行模式。在该模式中,只有 '\n' 行终止符在 . ^ 和 $ 的行为中被识别。也可以通过嵌入式标志表达式 (?d) 启用 UNIX 行模式。在以下步骤中,我们将修改测试工具 RegexTestHarness.java 以创建具有不区分大小写匹配的模式。
首先,修改代码以调用 compile 的备用版本:
Pattern pattern =
Pattern.compile(console.readLine("%nEnter your regex: "),
Pattern.CASE_INSENSITIVE);
然后编译并运行测试工具以获得以下结果:
Enter your regex: dog Enter input string to search: DoGDOg I found the text "DoG" starting at index 0 and ending at index 3. I found the text "DOg" starting at index 3 and ending at index 6.
如你所见,无论大小写如何,字符串文字“dog”都匹配这两种情况。要编译带有多个标志的模式,请使用按位或运算符 "|" 分隔要包含的标志。为清楚起见,以下代码示例对正则表达式进行硬编码,而不是从 Console 中读取它:
pattern = Pattern.compile("[az]$", Pattern.MULTILINE | Pattern.UNIX_LINES);
你也可以指定 int 变量:
final int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
Pattern pattern = Pattern.compile("aa", flags);
也可以使用 embedded flag expressions (嵌入式标志表达式) 启用各种标志。嵌入式标志表达式是 compile 的双参数版本的替代,并且在正则表达式本身中指定。以下示例使用原始测试工具 RegexTestHarness.java 和嵌入式标志表达式 (?i) 来启用不区分大小写的匹配。
Enter your regex: (?i)foo Enter input string to search: FOOfooFoOfoO I found the text "FOO" starting at index 0 and ending at index 3. I found the text "foo" starting at index 3 and ending at index 6. I found the text "FoO" starting at index 6 and ending at index 9. I found the text "foO" starting at index 9 and ending at index 12.
忽略大小写,所有匹配再次成功。
与 Pattern 的可公开访问的字段对应的嵌入式标志表达式如下表所示:
| 常量 | 等效嵌入式标志表达式 |
|---|---|
Pattern.CANON_EQ |
无 |
Pattern.CASE_INSENSITIVE |
(?i) |
Pattern.COMMENTS |
(?x) |
Pattern.MULTILINE |
(?m) |
Pattern.DOTALL |
(?s) |
Pattern.LITERAL |
无 |
Pattern.UNICODE_CASE |
(?u) |
Pattern.UNIX_LINES |
(?d) |
matches(String,CharSequence) 方法Pattern 类定义了一个方便的 matches 方法,该方法允许你快速检查给定输入字符串中是否存在模式。与所有公共静态方法一样,你应该通过其类名调用 matches,例如 Pattern.matches("\\d","1");。在此示例中,该方法返回 true,因为数字“1”与正则表达式 \d 匹配。
split(String) 方法split 方法是一个很好的工具,用于收集位于匹配模式两侧的文本。如下面 SplitDemo.java 所示,split 方法可以提取单词“one two three four five”从字符串“one:two:three:four:five”:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class SplitDemo {
private static final String REGEX = ":";
private static final String INPUT =
"one:two:three:four:five";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
String[] items = p.split(INPUT);
for(String s : items) {
System.out.println(s);
}
}
}
OUTPUT: one two three four five
为简单起见,我们匹配了字符串文字冒号(:)而不是复杂的正则表达式。由于我们仍在使用 Pattern 和 Matcher 对象,因此你可以使用 split 来获取位于任何正则表达式两侧的文本。这是相同的例子,SplitDemo2.java,修改为在数字上拆分:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class SplitDemo2 {
private static final String REGEX = "\\d";
private static final String INPUT =
"one9two4three7four1five";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
String[] items = p.split(INPUT);
for(String s : items) {
System.out.println(s);
}
}
}
OUTPUT: one two three four five
你可能会发现以下方法也有一些用处:
public static String quote(String s)返回指定 String 的文字模式 String。此方法生成 String,可用于创建与 String s 匹配的 Pattern,就像它是文字模式一样。输入序列中的元字符或转义序列将没有特殊含义。public String toString()返回此模式的 String 表示形式。这是编译此模式的正则表达式。java.lang.String 中的模式方法等价物java.lang.String 中也存在正则表达式支持,它通过几种模仿 java.util.regex.Pattern 行为的方法。为方便起见,下面介绍了 API 的主要片段。
public boolean matches(String regex):判断此字符串是否与给定的正则表达式匹配。调用 str.matches(regex) 形式的此方法会产生与表达式 Pattern.matches(regex, str) 完全相同的结果。public String[] split(String regex, int limit):围绕给定正则表达式的匹配拆分此字符串。调用 str.split(regex, n) 形式的此方法会产生与表达式 Pattern.compile(regex).split(str, n) 相同的结果。public String[] split(String regex):围绕给定正则表达式的匹配拆分此字符串。此方法与调用具有给定表达式且 limit 参数为零的双参数 split 方法的方法相同。结果数组中不包括尾随空字符串。还有一个替换方法,用另一个 CharSequence 替换一个:
public String replace(CharSequence target,CharSequence replacement):将此字符串中与 target 匹配的每个子字符串替换为指定的 replacement 序列。替换从字符串的开头到结尾,例如,在字符串“aaa”中将“aa”替换为“b”将导致“ba”而不是“ab”。