也不知道是谁首先将Regular Expression翻译成了"正则表达式"这么一个文诌诌的名词。无论是按字面还是按其用途,Regular Expression都应该是规则表达式,指对特定字符串构成规则/特征的描述。这种构成规则,也就是模式(Pattern)。
最早应用在Unix系统中的正则表达式尽管没有一个统一的权威标准,但各种正则表达式可说是大同、小异。
Java语言在JDK1.4版本中内置了java.util.regex,提供对正则表达式的支持, 其中包含Pattern、Matcher、PatternSyntaxException三个部分。
构成字符串的最基本元素是字符,正则表达式中,字符可以是字母/数字等可打印字符,也可以是回车/换行等控制字符。
字符 | |
---|---|
c | 字符c(可打印字符) |
\xhh | 16进制数值0xhh表示的字符。如字母'a'可以表示成0x61 |
\0vvv | 8进制数值0vvv表示的字符 |
\uhhhh | 16进制数值0xhhhh表示的Unicode字符 |
\t | 制表符(Tab, 0x09) |
\n | 换行符(LF, 0x0a) |
\r | 回车符(CR, 0x0d) |
\f | 换页符(FF, 0x0c) |
\e | 转义符(ESC, 0x1b) |
\cx | 控制字符x |
\\ | 字符'\'。字符'\'被用转义控制符,为了表示字符'\',就只好用'\\'表示 |
Java正则表达式中,还可以用'[...]'的形式表示一类特定字符中的一个。如[abc],指a或b或c;[0-9]表示数字0到9中的某一个;[abc[lmn]]表示a|b|c|l|m|n。[^abc]表示除a/b/c外的其他任意字符;[a-z-[bcd]]则表示从[a-z]的集合中减掉集合[bcd]...。
Java中,提供了一些内置的预定义字符类,以方便使用。
内置字符类 | |
---|---|
. | 除终止符外的其他任意单个字符。如果标志位DotAll有效,则表示任意字符 |
\d | 数字0-9,等同于[0-9] |
\D | 除数字0-9外的其他字符,等同于[^0-9]或[^\d] |
\s | 空白符,空格/制表/回车/换行/换页符,等同于[ \t\n\x0B\f\r] |
\S | 非空白符,等同于[^\s] |
\w | 英语中单词中所使用的字符,指a-z, A-Z, 0-9, 或连字符'-',等同于[0-9_A-Za-z] |
\W | 非单词字符,除\w外的其他字符[^\w] |
POSIX字符类(仅应用于us-ascii)
POSIX字符类 | |
---|---|
\p{Lower} | 小写字母, [z-z] |
\p{Upper} | 大写字母, [A-Z] |
\p{ASCII} | ASCII字符, [\x00-\x7f] |
\p{Alpha} | 字母, [\p{Lower}\p{Upper}] |
\p{Digit} | 数字, [0-9] |
\p{Alnum} | 字母或数字, [\p{Alpha}\p{Digit}] |
\p{Punct} | 标点, [!"#$%&'()*+,-./:;<=>?@[]\^_{}|~] |
\p{Graph} | 可见字符, [\p{Alnum}\p{Punct}] |
\p{Print} | 可打印字符, [\p{Graph}\s] |
\p{Blank} | 空格或制表符, [ \t] |
\p{Cntrl} | 控制字符, [\x00-\x1f\x7f] |
\p{XDigit} | 16进制的一位数字, [0-9a-fA-F] |
\p{Space} | 空白符号, [ \t\n\f\r\0x0b] |
\P{name}, name是以上名称中的一个. 表示名称name指定字符集外的字符, [^\p{name}] |
边界字符
边界符 | |
---|---|
^ | 输入起始;多行模式下,指一行的开始 |
$ | 输入结束;多行模式下,指一行的终止 |
\b | 单词的边界 |
\B | 非单词的边界 |
\A | 输入的开始 |
\z | 输入的结束 |
\Z | 最后结尾外的输入结束 |
\G | 上一个匹配的结束 |
引用控制:
\Q...\E | 逐字引用\Q和\E之间的字符 |
更多内置字符类, 可以在Java文档中java.util.regex.Pattern部分找到.
Java提供了一些逻辑操作符,用来对字符/字符类进行简单的逻辑操作
逻辑操作符 | |
---|---|
XY | 模式X后紧跟模式Y |
X|Y | X或者Y。从功能角度看,X|Y等同于字符类[XY],但从效率上看,字符类优于逻辑或。因此,应尽可能使用字符类而不是逻辑操作或。 |
&& | 与操作,求交集 |
^ | 求反/补集, 如上面的[^\d]等同于\D |
量词,用来对模式的匹配数量进行限制.
基本量词 | |
---|---|
? | 匹配0或1次 |
* | 匹配0或任意次 |
+ | 匹配1次或多次 |
{n} | 匹配n次 |
{n+} | 匹配n次或更多次 |
{n, m} | 匹配n到m次 |
量词在应用时,总是会结合它左边的第一个模式. 如,模式abc+,会匹配abc, abcc, abccc..., 而不会匹配abcabc. 因此, 括号的使用在某些情况下是必要的.
Java中,提供了三种不同量词匹配方式.
简单地说, 贪婪模式和占有模式相比, 贪婪模式会在只有部分匹配成功的条件下, 依次从多到少减少匹配成功部分模式的匹配数量, 将字符留给模式其他部分去匹配; 而占用模式则是占有所有能匹配成功部分, 绝不留给其他部分使用.
在字符串匹配中,通常还需要注意大小写,换行风格(win下是\r\n,unix/linux则是\n), Unicode等等。Java正则表达式中,可以通过(?idmsux)设定或通过(?-idmsux)取消标志,方便用户自行控制。
控制标志 | |
---|---|
i | 忽略大小写,也可在Pattern.compile方法中通过CASE_INSENSITIVE设置 |
d | Unix风格(\n)换行符,也可在Pattern.compile方法中通过UNIX_LINES设置 |
m | 多行模式,也可在Pattern.compile方法中通过MULTILINE设置 |
s | DotAll标志. 通配符.是否包括\n\r。也可在Pattern.compile方法中通过DOTALL设置 |
u | Unicode模式。也可在Pattern.compile方法中通过UNICODE_CASE设置 |
x | 注释标志. 在模式中可使用注释,并忽略模式中的空白符号和'#'号,直到模式尾部。也可在Pattern.compile方法中通过COMMENTS设置 |
在Pattern.compile()方法,还可以指定CANON_ON标志,用来定义匹配需遵守UNICODE等价规范。参考资料 |
分组, 即将将多个字符编组合在一起, 作为其他操作的一个逻辑单位. Java中, 以圆括号'(...)'作为分组的标识. 比如, 使用量词时,常会用到分组来指定要重复的单位.
Java正则表达式中, 分组可以分为捕获组(Capturing Group)和非捕获组(Non-Capturing Group)两类.
实际应用中, 对字符串进行匹配操作时, 除了字符串是否匹配模式的答案外, 常常还会关心诸如字符串中有多少与模式相匹配的子串, 与模式相匹配的子串到底是什么样等更具体的问题. 某些情况下, 前面的捕获结果还会直接成为后面捕获模式的一部分. 这些都 需要在匹配过程中,将实际匹配的子串储存起来(也许还需要计数), 以供随后可能的使用.
Java正则表达式中, 默认分组都是捕获组, 也即分组模式匹配的结果会被缓存起来. 在存在多个分组的模式中, Java从左到右扫描模式中的括号, 依次给存在的分组进行编号.
除了在完成匹配后使用Java所缓存的结果外, 在匹配开始前就可以在匹配模式中通过'\i'的形式引用第i个分组可能匹配到的实际字符串. 这种引用模式被称为后置引用(Back Quote).
并非所有分组的匹配结果都必须缓存。以'(?...)'形式指定的分组被称为非捕获组。匹配过程中,非捕获组所匹配的实际内存不会被缓存,匹配数量也不会被统计。因此,非捕获组不会获得组编号,也不能被反向引用。
非捕获组的几种形式
表达式 | 意义 |
---|---|
(?:X) | 指定模式X为非捕获组,但不保存其匹配结果。 如:(?:abc){3}匹配abcabcabc,但不缓存分组(abc)的匹配结果,更不能反向引用匹配结果 |
(?=X) | X为非捕获分组;并且,(?=X)匹配成功后不会占用任何字符!也即,形如(?=X)Y的模式中,子模式Y开始匹配的地方是非捕获组X匹配成功的开始处而不是结束处! 如:Jack(?=Sprat|Frost), 匹配字符串JackSprat中的Jack \w+(?=\d)匹配任何以数字结尾的单词,返回结果不包含数字 (?=two)three不能匹配字符串onetwothree,(?=two)([a-z])则会匹配以上字符串中的t |
Y(?!X) | X为非捕获分组,模式匹配任何后面不是X的Y。 如: Jack(?!Sprat>匹配JackFrost,但不会匹配JackSrpat \w+(?!\d)匹配任何不以数字结尾的单词,返回结果中不包含最后一个字符 |
(?<=X)Y | X为非捕获分组,模式匹配前面有X的Y。如使用量词,则量词所指定重复次数必须是一个有限集合。如(?<=foo)bar匹配foobar中的bar (?<=\w{2,3})\d匹配前面为2或3个单词字符的一位数字,如ab3中的3 (<=w+)\d非法,量词+可能匹配次数为无限。 |
(? | X为非捕获分组,模式匹配前面不是X的Y。如使用量词,则量词所指定重复次数必须是一个有限集合。如(?匹配任何不是以20开始的10 |
(?>X) | X为独立、非捕获分组。一旦X匹配成功,则不允许匹配引擎进行回退操作(贪婪模式下的吐字符)。 如:模式(?>[ab]*)\w\w,不能在字符串aabbaa中找到匹配子串。原因是(贪婪模式下)初次匹配时,[ab]*会将整个字符串占为己有,即使第一轮匹配失败也不会减少匹配量进行下一轮的尝试。而(?:[ab]*)\w\w)则可以匹配成功。 |