技术文章
- 使用正则表达式找出不包含特定字符串的条目
正则表达式工具
Expresso
RegexBuddy
正则表达式知识
字符,使用时另加\ | 解释 |
---|---|
x | 字符x(x可代表任何合法的字符) |
\0mnn | 八进制数0mnn所表示的字符 |
\xhh | 十六进制值0xhh所表示的字符 |
\uhhhh | 十六进制值0xhhhh所表示的UNICODE字符 |
\t | 制表符('\u0009') |
\n | 新行(换行)符('\u000A') |
\r | 回车符('\u000D') |
\f | 换页符('\u000C') |
\a | 报警(bell)符('\u0007') |
\e | Escape符('\u001B') |
\cx | x对应的控制符。例如\cM匹配Ctrl-M。x值必须为A~Z或a~z之一 |
特殊字符,转义才加\ | 解释 |
---|---|
$ | 匹配一行的结尾 |
^ | 匹配一行的开头 |
() | 标记子表达式的开始和结束位置 |
[] | 用于确定中括号表达式的开始和结束位置 |
{} | 用于标记前面子表达式的出现频度 |
* | 指定前面子表达式可以出现零次或多次 |
+ | 指定前面子表达式可以出现一次或多次 |
? | 指定前面子表达式可以出现零次或一次 |
. | 匹配除换行符\n之外的任何单字符 |
\ | 用于转义下一个字符,或指定八进制、十六进制字符 |
| | 指定两项之间任选一项 |
预定义字符,即通配符 使用时另加\ |
说明 |
---|---|
. | 可以匹配任何字符 |
\d | 匹配0-9的所有数字 |
\D | 匹配非数字 |
\s | 匹配所有的空白字符,包括空格、制表、回车、换页、换行 |
\S | 匹配所有的非空白字符 |
\w | 匹配所有的单词字符,包括0-9、26个英文字母和下划线 |
\W | 匹配所有的非单词字符 |
方括号表达式 | 说明 |
---|---|
表示枚举 | 如[abc]表示abc中任意一字符 |
表示范围:- | 如[a-f]表示a~f范围内任意字符 |
表示求否:^ | 如[^abc]表示非abc的任意字符 |
表示“与”运算:&& | 如[a-z&&[^bc]]表示a-z范围内除bc外的所有字符 |
表示“并”运算 | 如[a-d[m-p]]表示[a-dm-p] |
边界匹配符 | 说明 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词的边界 |
\B | 非单词的边界 |
\A | 输入的开头 |
\G | 前一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符 |
\z | 输入的结尾 |
- Greedy(贪婪模式):数量表示符默认采用贪婪模式,表达式会一直匹配下去,直到无法匹配为止
- Reluctant(勉强模式):用问题后缀表示,只会匹配最少的字符,也称最小匹配模式
- Possessive(占有模式):用加号后缀表示,目前只有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次 |
前瞻与后顾
正则表达式中有前瞻(Lookahead)和后顾(Lookbehind)的概念,这两个术语非常形象的描述了正则引擎的匹配行为。需要注意一点,正则表达式中的前和后和我们一般理解的前后有点不同。一段文本,我们一般习惯把文本开头的方向称作“前面”,文本末尾方向称为“后面”。但是对于正则表达式引擎来说,因为它是从文本头部向尾部开始解析的(可以通过正则选项控制解析方向),因此对于文本尾部方向,称为“前”,因为这个时候,正则引擎还没走到那块,而对文本头部方向,则称为“后”,因为正则引擎已经走过了那一块地方。
所谓的前瞻就是在正则表达式匹配到某个字符的时候,往“尚未解析过的文本”预先看一下,看是不是符合/不符合匹配模式,而后顾,就是在正则引擎已经匹配过的文本看看是不是符合/不符合匹配模式。符合和不符合特定匹配模式我们又称为肯定式匹配和否定式匹配。
现代高级正则表达式引擎一般都支持都支持前瞻,对于后顾支持并不是很广泛。
捕获组
字符 | 描述 | 示例 |
---|---|---|
(pattern) | 匹配pattern并捕获结果,自动设置组号。 | (abc)+d 匹配abcd或者abcabcd |
(? |
匹配pattern并捕获结果,设置name为组名。 | |
\num | 对捕获组的反向引用。其中 num 是一个正整数。 | (\w)(\w)\2\1 匹配abba |
\k |
对命名捕获组的反向引用。其中 name 是捕获组名。 | (? 匹配xabcx |
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个捕获组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
也可以自己指定子表达式的组名。这样在表达式或程序中可以直接引用组名,当然也可以继续使用组号。但如果正则表达式中同时存在普通捕获组和命名捕获组,那么捕获组的编号就要特别注意,编号的规则是先对普通捕获组进行编号,再对命名捕获组进行编号。
非捕获组
字符 | 描述 | 示例 |
---|---|---|
(?:pattern) | 匹配pattern,但不捕获匹配结果。 | industr(?:y\|ies) 匹配"industry"或"industries" |
(?=pattern) | 零宽度正向预查,不捕获匹配结果。 | Windows(?=95\|98\|NT\|2000) 匹配 "Windows2000" 中的 "Windows" 不匹配"Windows3.1" 中的 "Windows" |
(?!pattern) | 零宽度负向预查,不捕获匹配结果 | Windows(?!95\|98\|NT\|2000) 匹配"Windows3.1"中的"Windows" 不匹配"Windows2000"中的 "Windows" |
(?<=pattern) | 零宽度正向回查,不捕获匹配结果。 | 2000(?<=Office\|Word\|Excel) 匹配"Office2000" 中的"2000" 不匹配 "Windows2000"中的 "2000" |
(? | 零宽度负向回查,不捕获匹配结果。 | 2000(? |
非捕获组只匹配结果,但不捕获结果,也不会分配组号,当然也不能在表达式和程序中做进一步处理。
首先(?:pattern)与(pattern)不同之处只是在于不捕获结果。
接下来的四个非捕获组用于匹配pattern(或者不匹配pattern)位置之前(或之后)的内容。匹配的结果不包括pattern。
例如:
(?<=<(\w+)>).*(?=\1>)匹配不包含属性的简单HTML标签内的内容。如:
之中的hello,匹配结果不包括前缀
。
注释
字符 | 描述 | 示例 |
---|---|---|
(?#comment) | comment是注释,不对正则表达式的处理产生任何影响 | 2[0-4]\d(?#200-249)\|25[0-5](?#250-255)\|1?\d\d?(?#0-199) 匹配0-255的整数 |
使用正则表达式
Java篇
java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。
它包括两个类:Pattern和Matcher。
Pattern是一个正则表达式编译后在内存中的表现形式。 正则表达式字符串必须先被编译为Pattern对象,然后再利用该Pattern对象创建对应的Matcher对象。执行匹配所涉及的状态保留在Matcher对象中,多个Match对象可共享同一个Pattern对象
Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。
典型的调用程序如下:
import java.util.regex.Pattern
//将一个字符串编译成Pattern对象
Pattern p = Pattern.compile("a*b");
//使用Pattern对象创建Matcher对象
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
上面定义的Pattern对象可以多次重复使用。如果某个正则表达式仅需一次使用,则可用Pattern类的静态matches方法,此方法自动把指定字条串编译成匿名的Pattern对象,并执行匹配
boolean b = Pattern.matches("a*b", "aaaaab");
Pattern是不可变类,可供多个并发线程安全使用。
Matcher类提供了如下几个常用方法:
- find()返回目标字符串中是否包含与Pattern匹配的子串
- group():返回上一次与Pattern匹配的子串
- start():返回上一次与Pattern匹配的子串在目标字符串中的开始位置
- end():返回上一次与Pattern匹配的子串在目标字符串中的结束位置加1
- lookingAt():返回目标字符串起始部分与Pattern是否匹配
- matches():返回整个目标字符串与Pattern是否匹配,完全匹配才返回true
- reset():将现有的Matcher对象应用于一个新的字符序列
通过Matcher类的find()和group()方法从目标字符串中依次取出特定子串:
//创建一个Pattern对象,并用它建立一个Matcher对象
Matcher m = Pattern.compile("\\w+").matcher("Java is very easy!");
while(m.find()){
System.out.println(m.group());
}
int i = 0;
//find()方法可以传入一个int类型的参数,从该int索引处向下搜索
while(m.find(i)){
System.out.print(m.group() + "\t");
i++;
}
//start()和end()方法主要用于确定子串在目标字符串中的位置
while(m.find()){
System.out.println(m.group() + "子串的起始位置:" + m.start() + ",其结束位置" + m.end());
}
//reset()将现有的Matcher对象应用于新的字符序列
Pattern p = Pattern.compile("\\w+");
Matcher m = Pattern.matcher("King");
m.reset("Yes");
String提供了如下几个特殊的方法
- boolean matches(String regex):判断该字符串是否匹配指定的正则表达式
- String replaceAll(String regex, String replacement):将该字符串中所有匹配regex的子串替换成replacement。
- String replaceFirst(String regex, String replacement):将该字符串中第一个匹配regex的子串替换成replacement。
- String[] split(String regex):以regex作为分隔符,把该字符串分割成多个子串。