您的位置:首页 > 其它

正则表达式

2015-05-29 09:03 141 查看

1、句点符号

假设在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。要构造出这个正则表达式,可以使用一个通配符——句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格、Tab字符甚至换行符

2、方括号符号

为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号(“[]”)里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因为在方括号之内只能匹配单个字符

此外,方括号内还可以用“-”表示跨度,如“[a-g]”匹配字母表中a到g的小写字母,“[1-9]”匹配1到9的数字。

可以使用“&&”取交集,比如“[1-9&&[^456]]”,匹配1到9中除了4、5、6以外的数字。

3、“或”符号

如果除了上面匹配的所有单词之外,还想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意义就是“或”运算。要匹配“toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括号还可以用来分组。

4、表示匹配次数的符号

? 0次或1次

+ 1次或多次,即至少1次

* 0次或多次,即任意多次

{n} 恰好n次

{n,m} n次到m次

假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如下图所示。在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。



假设进行搜索的时候希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,可以在连字符号后面加上“?”数量限定符号,如下图所示:



5、“否”符号

“^”符号称为“否”符号。如果用在方括号内,“^”表示不想要匹配的字符。例如,下图的正则表达式匹配所有单词,但以“X”字母开头的单词除外。



6、圆括号

(1)限定量词作用的范围



(cat)? 匹配0个或1个“cat”

(cat)+ 匹配1个或多个“cat”

(2)限定多选结构的范围



(cat|dog) 匹配“cat”或“dog”

(3)分组捕获

位于圆括号之间的模式匹配的内容都会被捕获,当模式中有嵌套的圆括号时,变量的编号会按照圆开括号出现的位置一次进行。



([A-Za-z](\d{2}))((-)\d{2})匹配”A22-33”时,匹配情况如下:

第一个出现的圆括号中的正则表达式为:[A-Za-z](\d{2})

匹配结果Group 1: A22

第二个出现的圆括号中的正则表达式为:\d{2}

匹配结果Group 2: 22

第三个出现的圆括号中的正则表达式为:(-)\d{2}

匹配结果Group 3: -33

第四个出现的圆括号中的正则表达式为:-

匹配结果Group 4: -

(4)分组不捕获

当圆括号与“?:”组合使用时,表示非捕获型分组。圆括号的内容不作为捕获对象,当圆括号中的内容不是想捕获的对象时,采用非捕获圆括号可以提高匹配效率。



(\w(?:\d{2}))((?:-)\d{2})匹配” A22-33”情况如下:

Group 1: A22

Group 2: -33

注:\d{2}匹配的”22”没有被捕获,-匹配的“-”也没有被捕获。

(5)反向引用捕获文本



([ab])\1,圆括号内的“[ab]” 可以匹配“a”或“b”,后面的“\1”代表,如果前面匹配的文本引用。如果捕获组匹配到“a”,那么反向引用也就只能匹配“a”,同理,如果捕获组匹配到的是“b”,那么反向引用也就只能匹配“b”。由于后面反向引用“\1”的限制,要求必须是两个相同的字符,在这里也就是“aa”或者“bb”才能匹配成功。

(6)前瞻

当圆括号与“?=”组合使用时,表示前瞻,代表该表达式会作为匹配校验,但不会出现在匹配结果字符串里面。



(John) (?=Resig)匹配情况如下:

John:不匹配,因为后面没有跟着Resig

John Backus:不匹配,后面跟着的不是Resig

John Reisg:匹配,John后面跟着Resig。但是匹配的结果是“John”而不是“JohnReisg”。

7、预定义字符

\d 数字字符:[0-9]

\D 非数字字符:[^0-9]

\s 空白字符:[\t\n\x0B\f\r]

\S 非空白字符:[^\s]

\w 单词字符:[a-zA-Z_0-9]

\W 非单词字符:[^\w]

8、边界匹配字符

^ 行首

$ 行尾

\b 单词边界

\B 非单词边界

\A 输入的开头

\G 上一个匹配的结尾

\Z 输入的结尾,仅用于最后的结束符(如果有的话)

\z 输入的结尾

9、匹配模式

正则表达式有三种匹配模式:贪婪(greedy)、勉强(reluctant)和侵占(possessive)

贪婪 勉强 侵占

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 次



假定要分析的字符串是:xfooxxxxxxfoo

模式:.*foo (贪婪模式):

模式分为子模式p1(.*)和子模式p2(foo)两个部分. 其中p1中的量词匹配方式使用默认方式(贪婪型)。匹配开始时,吃入所有字符xfooxxxxxxfoo去匹配子模式p1。匹配成功,但这样以来就没有了字符串去匹配子模式p2。本轮匹配失败;第二轮:减少p1部分的匹配量,吐出最后一个字符, 把字符串分割成xfooxxxxxxfo和o两个子字符串s1和s2。 s1匹配p1, 但s2不匹配p2。本轮匹配失败;第三轮,再次减少p1部分匹配量,吐出两个字符,字符串被分割成xfooxxxxxxfo和oo两部分。结果同上。第四轮,再次减少p1匹配量,
字符串分割成xfooxxxxxx和foo两个部分,,这次s1/s2分别和p1/p2匹配。停止尝试,返回匹配成功。

模式:.*?foo (勉强模式): 最小匹配方式。第一次尝试匹配, p1由于是0或任意次,因此被忽略,用字符串去匹配p2,失败;第二次,读入第一个字符x,尝试和p1匹配,,匹配成功;字符串剩余部分fooxxxxxxfoo中前三个字符和p2也是匹配的。因此,停止尝试,返回匹配成功。在这种模式下,如果对剩余字符串继续去寻找和模式相匹配的子字符串,还会找到字符串末尾的另一个xfoo,而在贪婪模式下,由于第一次匹配成功的子串就已经是所有字符,因此不存在第二个匹配子串。

模式:.*+foo (侵占模式): 也叫占用模式。匹配开始时读入所有字符串,和p1匹配成功, 但没有剩余字符串去和p2匹配。因此,匹配失败。返回。

简单地说,贪婪模式和占有模式相比, 贪婪模式会在只有部分匹配成功的条件下,依次从多到少减少匹配成功部分模式的匹配数量,将字符留给模式其他部分去匹配;而占用模式则是占有所有能匹配成功部分,绝不留给其他部分使用。

占用模式目前只有java支持,通常比较少用。

Java中的正则表达式API

JDK中与正则表达式相关的类位于java.util.regex包下。有两个类Pattern和Matcher。

Pattern类

方法摘要:

static Pattern compile(String regex)

将给定的正则表达式编译到模式中。

static Pattern compile(String regex, int flags)

将给定的正则表达式编译到具有给定标志的模式中。

Matcher matcher(CharSequenceinput)

创建匹配给定输入与此模式的匹配器。CharSequence是一个接口,String,StringBuffer,StringBuilder都是其实现类。

static boolean matches(String regex, CharSequence input)

编译给定正则表达式并尝试将给定输入与其匹配。

String[] split(CharSequenceinput)

围绕此模式的匹配拆分给定输入序列。

String[] split(CharSequenceinput, int limit)

围绕此模式的匹配拆分给定输入序列。

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-awarecase folding)大小写。在指定此标志后,需要通过 CASE_INSENSITIVE 标志来启用,不区分大小写区配将在 Unicode 标准的意义上来完成。默认情况下,不区分大小写匹配仅匹配 US-ASCII 字符集中的字符。可折叠感知 Unicode 大小写也能通过内嵌标志表达式(?u)来启用。指定此标志可能会对性能会有一定的影响。

Pattern.UNIX_LINES

  启用 Unix 行模式。在这种模式下,.、^和$的行为仅识别“\n”的行结束符。Unix 行模式可以通过内嵌标志表达式(?d)来启用。

Matcher类

方法摘要:

int end()

返回最后匹配字符之后的偏移量。

int end(intgroup)

返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。

boolean find()

尝试查找与该模式匹配的输入序列的下一个子序列。

boolean find(intstart)

重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。

String group()

返回由以前匹配操作所匹配的输入子序列。

String group(intgroup)

返回在以前匹配操作期间由给定组捕获的输入子序列。

int groupCount()

返回此匹配器模式中的捕获组数。

boolean matches()

尝试将整个区域与模式匹配。

Pattern pattern()

返回由此匹配器解释的模式。

String replaceAll(Stringreplacement)

替换模式与给定替换字符串相匹配的输入序列的每个子序列。

String replaceFirst(Stringreplacement)

替换模式与给定替换字符串匹配的输入序列的第一个子序列。

Matcher reset()

重置匹配器。

Matcher reset(CharSequenceinput)

重置此具有新输入序列的匹配器。

int start()

返回以前匹配的初始索引。

int start(intgroup)

返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引。

MatchResult toMatchResult()

作为 MatchResult 返回此匹配器的匹配状态。

Matcher usePattern(PatternnewPattern)

更改此 Matcher 用于查找匹配项的Pattern。

实例

String regex  = "((A+)(B(C)))";

String input ="ABC-AABC-AAAAABCD";

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);

int groupCount =matcher.groupCount();
//regex被圆括号分为四组,按照括号的出现位置,分别为:((A+)(B(C)))、(A+)、(B(C))、(C)
//匹配的时候,还是按照A+BC 去搜索,只不过,每次匹配成功后,会将搜到的字符串按照上面的四组规则分为四个子串,存储起来
while(matcher.find()){
System.out.print("匹配结果:");
for(inti=0;i<groupCount;i++){
System.out.print("group"+i+":"+matcher.group(i)+"\t");
}
System.out.println();
}


输出:

匹配结果:group0:ABC group1:ABC group2:A group3:BC

匹配结果:group0:AABC group1:AABC group2:AA group3:BC

匹配结果:group0:AAAAABC group1:AAAAABC group2:AAAAA group3:BC

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: