8 Pattern 类的方法
到目前为止,仅使用测试用具来建立最基本的 Pattern 对象。在这一节中,我们将探讨一些诸如使用标志构建模式、使用内嵌标志表达式等高级的技术。同时也探讨了一些目前还没有讨论过的其他有用的方法。
8.1 使用标志构建模式
Pattern 类定义了备用的 compile 方法,用于接受影响模式匹配方式的标志集。标志参数是一个位掩码,可以是下面公共静态字段中的任意一个:
Pattern.CANON_EQ
启用规范等价。在指定此标志后,当且仅当在其完整的规范分解匹配时,两个字符被视为匹配。例如,表达式a\u030A
[8]在指定此标志后,将匹配字符串“\u00E5”(即字符 )。默认情况下,匹配不会采用规范等价。指定此标志可能会对性能会有一定的影响。
Pattern.CASE_INSENSITIVE
启用不区分大小写匹配。默认情况下,仅匹配 US-ASCII 字符集中的字符。Unicode 感知(Unicode-aware)的不区分大小写匹配,可以通过指定 UNICODE_CASE 标志连同此标志来启用。不区分大小写匹配也能通过内嵌标志表达式(?i)
来启用。指定此标志可能会对性能会有一定的影响。
Pattern.COMMENTS
模式中允许存在空白和注释。在这种模式下,空白和以#
开始的直到行尾的内嵌注释会被忽略。注释模式也能通过内嵌标志表达式(?x)
来启用。
Pattern.DOTALL
启用 dotall 模式。在 dotall 模式下,表达式.
匹配包括行结束符在内的任意字符。默认情况下,表达式不会匹配行结束符。dotall 模式也通过内嵌标志表达式(?x)
来启用。[s 是“单行(single-line)”模式的助记符,与 Perl 中的相同。]
Pattern.LITERAL
启用模式的字面分析。指定该标志后,指定模式的输入字符串作为字面上的字符序列来对待。输入序列中的元字符和转义字符不具有特殊的意义了。
CASE_INSENSITIVE 和 UNICODE_CASE
与此标志一起使用时,会对匹配产生一定的影响。其他的标志就变得多余了。启用字面分析没有内嵌标志表达式。
Pattern.MULTILINE
启用多行(multiline)模式。在多行模式下,表达式^
和$
分别匹配输入序列行结束符前面和行结束符的前面。默认情况下,表达式仅匹配整个输入序列的开始和结尾。多行模式也能通过内嵌标志表达式(?m)
来启用。
Pattern.UNICODE_CASE
启用可折叠感知 Unicode(Unicode-aware case folding)大小写。在指定此标志后,需要通过
CASE_INSENSITIVE 标志来启用,不区分大小写区配将在 Unicode 标准的意义上来完成。默认情况下,不区分大小写匹配仅匹配
US-ASCII 字符集中的字符。可折叠感知 Unicode 大小写也能通过内嵌标志表达式(?u)
来启用。指定此标志可能会对性能会有一定的影响。
Pattern.UNIX_LINES
启用 Unix 行模式。在这种模式下,.
、^
和$
的行为仅识别“\n”的行结束符。Unix 行模式可以通过内嵌标志表达式(?d)
来启用。
接下来,将修改测试用具 RegexTestHarness.java,用于构建不区分大小写匹配的模式。
首先,修改代码去调用 complie 的另外一个备用的方法:
Pattern pattern = Pattern.compile(
console.readLine("%nEnter your regex: "),
Pttern.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”的都产生了匹配。使用多个标志来编译一个模式,使用按位或操作符“|”分隔各个标志。为了更清晰地说明,下面的示例代码使用硬编码(hardcode)的方式,来取代控制台中的读取:
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);
8.2 内嵌标志表达式
使用内嵌标志表达式(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) |
8.3 使用 matches(String, CharSequence) 方法
Pattern 类定义了一个方便的 matches
方法,用于快速地检查模式是否表示给定的输入字符串。与使用所有的公共静态方法一样,应该通过它的类名来调用 matches 方法,诸如
Pattern.matches("\\d","1");。这个例子中,方法返回 true,这是由于数字“1”匹配了正则表达式\d
。
8.4 使用 split(String) 方法
split 方法是一个重要的工具,用于收集依赖于被匹配的模式任一边的文本。如下面的 SplitDemo.java 所示,split 方法能从“one:two:three:four:five”字符串中解析出“one two three four five”单词:
import java.util.regex.Pattern;
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);
}
}
}
输出:
one two three four five
简而言之,已经使用冒号(:
)取代了复杂的正则表达式匹配字符串文字。以后仍会使用 Pattern 和 Matcher 对象,也能使用 split 得到位于任意正则表达式各边的文本。下面的 SplitDemo2.java 是个一样的例子,使用数字作为 split 的参数:
import java.util.regex.Pattern;
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);
}
}
}
输出:
one two three four five
8.5 其他有用的方法
你可以从下面的方法中找到比较好用的方法:
8.6 在 java.lang.String 中等价的 Pattern 方法
java.lang.String 通过模拟 java.util.regex.Pattern 行为的几个方法,也可以支持正则表达式。方便起见,下面主要摘录了出现在 API 关键的方法。
还有一个替换方法,把一个 CharSequence 替换成另外一个: