关于正则表达式的小笔记
1.1概述
正则表达式是一种强大而灵活的文本处理工具。使用正则表达式,我们能够以编程的方式,构造复杂的文本模式,并对输入的字符串进行搜索。一旦找到了相匹配的部分,就能随心所欲进行处理。
在java语言中的正则表达式对反斜杠\有着与其它语言不同的处理。其它语言中,\\表示“想要在正则表达式中插入一个普通的反斜线,没有任何特殊的意义”;而在java中,\\表示“要插入一个正则表达式的反斜线,因此其后的字符具有特殊的意义。”如:表示一位数字,用\\d表示。
1.2创建正则表达式
表1-1
字符 | |
B | 指定字符B |
\xhh | 十六进制值为oxhh的字符 |
\uhhhh | 十六进制表示为oxhhhh的Unicode |
\t | 制表符Tab |
\n | 换行符 |
\r | 回车 |
\f | 换页 |
\e | 转义(Escape) |
只有学会使用字符类之后,正则表达式的威力才能真正显现出来。以下是一些创建字符类的典型方式。
表1-2
字符 | |
. | 任意字符 |
[abc] | 包含a、b和c的任意字符(和a|b|c作用相同) |
[^abc] | 除了a、b和c之外的任何字符(否定) |
[a-zA-Z] | 从a到z或从A到Z的任何字符(范围) |
[abc[hij]] | 任意a、b、c、h、i和j字符(和a|b|c|h|i|j作用相同) |
[a-z&&[hij]] | 任意h、i或j(相交) |
\s | 空白符(空格、tab、换行、换页和回车) |
\S | 非空白符([^\S]) |
\d | 数字[0-9] |
\D | 非数字[^0-9] |
\w | 词字符[a-zA-Z0-9] |
\W | 非词字符[^\w] |
表1-3
逻辑操作符 | |
XY | Y跟在X后面 |
X|Y | X或Y |
(X) | 捕获组,可以在表达式中用\i引用第i个捕获组 |
表1-4
边界匹配符 | |
^ | 一行的起始 |
$ | 一行的结束 |
\b | 词的边界 |
\B | 非词的边界 |
\G | 前一个匹配的结束 |
举个例子:
public class Demo{
public static void main(String[] args){
for(String str:new String[]{"Rudolph","[rR]udolph","[rR][aeiou][a-z]ol.*","R.*"}){
System.out.println("Rudolph".matches(str));
}
}
}
[rR]udolph:r或R开头;
[rR][aeiou][a-z]ol.*:r或R开头,第二个字母[aeiou]中一个,第三个[a-z]中一个,后接ol,最后为任意字符;
R.*:R打头的任意字符串。
1.3量词
量词描述了一个模式吸收输入文本的方式:
- 贪婪型:量词总是贪婪的,除非有其他的选项被设置。贪婪表达式会为所有可能的模式发现尽可能多的匹配。假如现有模式仅能匹配第一个可能的字符组,如果它是贪婪的,那么它就会继续匹配下去。
- 勉强型:用问号来指定,这个量词匹配满足模式所需的最少字符数。所以也称为懒惰的、最少匹配的和非贪婪的。
- 占有型:这种类型只有在java语言中才可用,当正则表达式被应用于字符串时,它会产生相当多的状态,以便在匹配失败时可以回溯。常用于防止正则表达式失控。
贪婪型 | 勉强型 | 占有性 | 匹配 |
X? | X?? | X?+ | 一个或零个X |
X* | X*? | X*+ | 零个或多个X |
X+ | X+? | X++ | 一个或多个X |
X{n} | X{n}? | X{n}+ | X恰好出现n次 |
X{n,} | X{n,}? | X{n,}+ | X至少出现n次 |
X{n,m} | X{n,m}? | X{n,m}+ | X至少出现n次,且不超过m次 |
注:这里的表达式X,要使用圆括号括起来,如(abc)+。
1.4Pattern和Matcher
虽然String类中也能使用正则表达式,但其功能有限,所以更愿意使用功能强大的regex包下的Pattern.complie()方法来编译正则表达式。
- 会更根据正则表达式生成一个Pattern对象;
- 然后将要检索的字符串传入Pattern对象的matcher()方法;
- matcher()方法会生成一个Matcher对象。
public class Test{
public static void main(String[] args){
for(String str : args){
Pattern p = Pattern.compile(str);
Matcher m = p.matcher(args[0]);
while(m.find()){
m.group();
m.start();
m.end();
}
}
}
}
1.4.1 find()
Matcher.find()方法可用来在Test中查找多个匹配,find()对字符串进行匹配,匹配到的字符串可以在任何位置。
find(int i) 重置匹配器,然后尝试查找匹配该模式、并以指定索引i开始匹配。如下代码:
@Test
public void run(){
String s = "hello world";
Pattern p = Pattern.compile("\\w+");
Matcher m = p.matcher(s);
int i = 0;
while(m.find(i)){
System.out.println(m.group());
i++;
}
}
/*output
hello
ello
llo
lo
o
world
world
orld
rld
ld
d
*/
1.4.2 组(groups)
Matcher对象提供了一系列方法,用以获取与组相关的信息:
- l int groupCount()返回该匹配器的模式中分组数目;
- l String group(int group)返回在以前匹配操作期间由给定组捕获的输入子序列。
- l int start()返回以前匹配的起始位置的索引。
- l int start(int group)返回在以前的匹配操作期间,由给定组所捕获的子序列的起始索引。
- l int end()返回最后匹配字符的索引加一的值。
- l int end(int group)返回在前一次匹配操作中,寻找到组的最后一个字符索引加一的值。
- l boolean matches()只有在完全匹配正则表达式才会返回true。
- l boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配,只要输入的第一部分匹配就返回true。
1.5split()
split()方法将输入字符串断开成字符串对象数组,断开边界由下列正则表达式确定:
- l String[]split(CharSequence input)围绕此模式的匹配拆分给定输入序列。
- l String[]split(CharSequence input, int limit)围绕此模式的匹配拆分给定输入序列。注:limit可限定通过分割符分割后的字符串数量。
1.6替换操作
- l String replaceAll(Stringreplacement)替换模式与给定替换字符串相匹配的输入序列的每个子序列。
- l String replaceFirst(Stringreplacement)替换模式与给定替换字符串匹配的输入序列的第一个子序列。
- l Matcher appendReplacement(StringBuffersb, String replacement)执行渐进式的替换。
- l StringBufferappendTail(StringBuffer sb)在执行一次或多次appendReplacement()之后,此方法可以将匹配完后剩下的部分复制到sb中。
1.7reset()
Matcher reset()方法可以重置匹配器,将现有的Matcher对象应用于一个新的字符序列。
1.8Pattern标记
static Pattern compile(String regex, int flags)将给定的正则表达式编译到具有给定标志的模式中。
编译标记 | 效果 |
Pattern.CANON_EQ | 两个字符当且仅当它们的完全规范分解相匹配时,就认为它们是匹配的。例如,如果我们指定这个标记,表达式a\u030A就会匹配字符串?。在默认的情况下,匹配不考虑规范的等价性。 |
Pattern.CASE_INSENSITIVE(?i) | 默认情况下,大小写不敏感的匹配假定只有US-ASCII字符集中的字符才能进行。这个标记允许模式匹配不必考虑大小写(大写或小写)。通过指定UNICODE_CASE标记及结合此标记。基于Unicode的大小写不满干的匹配就可以开启了。 |
Pattern.COMMENTS(?x) | 在这种模式下,空格符将被忽略掉,并且以#开始直到行末的注释也会被忽略掉。通过嵌入的标记表达式也可以开启Unix的行模式X。 |
Pattern.DOTALL(?s) | 在dotall模式中,表达式"." 匹配所有字符,包括终结符。默认情况下,”." 表达式不匹配行终结符。 |
Pattern.MULTILINE(?m) | 在多行模式下,表达式^和$分别匹配一行的开始和结束。^还匹配输入字符串的开始,而$还匹配输入字符串的结尾。默认情况下,这些表达式仅匹配输入的完整字符串的开始和结束。 |
Pattern.UNICODE_CASE(?u) | 当指定这个标记, 并且开启CASE_INSENSITIVE时,大小写不敏感的匹配将按照与Unicode标准相一致的方式进行。默认情况下,大小写不敏感的匹配假定只能在US-ASCII 字符集中 |
Pattern.UNIX_LINES(?d) | 在这种模式下,在., ^和$行为中, 只识别行终结符\n |
以上表格摘自《java编程思想》