加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

正则表达式的环视和匹配

发布时间:2020-12-14 04:33:46 所属栏目:百科 来源:网络整理
导读:环视 环视匹配的最终结果就是一个位置,有四种类型的环视: (?=Expression) 顺序肯定环视,表示所在位置右侧能够匹配Expression (?!Expression) 顺序否定环视,表示所在位置右侧不能匹配Expression (?=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Ex


环视

  环视匹配的最终结果就是一个位置,有四种类型的环视:

  (?=Expression) 顺序肯定环视,表示所在位置右侧能够匹配Expression

  (?!Expression) 顺序否定环视,表示所在位置右侧不能匹配Expression

  (?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expression

  (?<!Expression) 逆序否定环视,表示所在位置左侧不能匹配Expression


  可以用以下两个正则表达式理解环视:

  (1)字母、数字、特殊符号全部出现,至少8位

Patternpattern=Pattern.compile("^(?=.*[d]+)(?=.*[a-zA-Z]+)(?=.*[#$_!]+)[w#$!]{8,}$");
Matchermatcher=pattern.matcher("123456a890#");
while(matcher.find()){
System.out.println(matcher.group());
}

  表达式的意思是开头位置应该是这样一个位置,后面有数字、字母、特殊符号,然后后面有至少8个指定的字符。

 (2)字母、数字、特殊符号至少出现两种,6-20位

Patternpattern=Pattern.compile("^(?![d]+$)(?![a-zA-Z]+$)(?![!#$%^&*]+$)[da-zA-Z!#$%^&*]{6,20}$");
Matchermatcher=pattern.matcher("aaaaaaaaaaa!");
while(matcher.find()){
System.out.println(matcher.group());
}

  表达式的意思是开头和结尾中间不能全是数字,不能全是字母,不能全是特殊符号,然后是指定的字符出现6到20次。


三种匹配方式

  匹配优先(贪婪匹配)

  忽略优先(懒惰匹配)

  占有优先


  理解这三种方式的关键在于理解回溯,下面的代码辅助理解这三种方式:

publicstaticvoidmain(String[]args)
{
Patternpattern=Pattern.compile("a.*a");
Matchermatcher=pattern.matcher("ababa");
if(matcher.find())
{
System.out.println(matcher.group());
}
else
{
System.out.println("不匹配");
}

pattern=Pattern.compile("a.*?a");
matcher=pattern.matcher("ababa");
if(matcher.find())
{
System.out.println(matcher.group());
}
else
{
System.out.println("不匹配");
}

pattern=Pattern.compile("a.*+a");
matcher=pattern.matcher("ababa");
if(matcher.find())
{
System.out.println(matcher.group());
}
else
{
System.out.println("不匹配");
}
}

输出:

ababa
aba
不匹配


固化分组和占有匹配

  下面的文字和例子取值《精通正则表达式》

  假设我们有这样的问题,把类似 3.690000023 的小数保留两位小数,类似 2.3563895 的小数保留三位小数,也就是说如果小数的第三位是0,则保留两位小数,如果是非0,就保留三位小数。

$number=~s/(.dd[1-9]?)d*/$1/;

  这个表达式完全可以工作,美中不足的一点是,当 $number 类似 3.695 的时候,我们把 .695 替换为了 .695,浪费了工夫。为了解决这个问题,我们把表达式稍稍修改一下。

$number=~s/(.dd[1-9]?)d+/$1/;

  仅仅把星号替换成了加号,这样表示括号外至少有一位数字的时候才进行替换。看上去很完美,但是却出现了致命的错误,.695 被替换成了 .69了。这是为什么呢?在表达式 (.dd[1-9]?) 匹配了 .695 后, 后面的 d+ 无法匹配了,为了使整个表达式匹配成功,引擎必须回溯,[1-9]?必须把匹配的数字吐出去,所以 5 被 d+ 匹配了。这就是回溯造成的问题。事实上在这种情况下,我们不希望引擎回溯,有两种办法可以强迫引擎放弃回溯,固化分组和占有量词。

$number=~s/(.dd(?>[1-9]?))d+/$1/;#固化分组

$number=~s/(.dd[1-9]?+)d+/$1/;#占有量词

  引擎放弃回溯后, 上面的表达式将无法匹配 .695,这正是我们想要的。

  占有优先量词与匹配优先量词很相似,只是它们从来不交还已经匹配的字符。

  你也许会想,占有优先量词和固化分组关系非常紧密。像「w++」这样的占有优先量词与「(?>w+)」的匹配结果完全相同,只是写起来更加方便而已。使用占有优先量词,「(.dd(?>[1-9]?))d+」写做「(.dd[1-9]?+)^d+」。

  请务必区分「(?>M)+」和「(?M+)」。前者放弃「M」创建的备用状态,因为「M」不会制造任何状态,所以这样做没什么价值。而后者放弃「M+」创造的未使用状态,这样做显然有意义。

  比较「(?>M)+」和「(?>M+)」,显然后者就对应于「M++」,但如果表达式很复杂,例如

("|[^"])*+

  从占有优先量词转换为固化分组时,大家往往会想到在括号中添加‘?>’得到 (?>"|[^"])*。这个表达式或许有机会实现你的目的,但它显然不等于那个使用占有优先量词的表达式;它就好像是把「M++」写作「(?>M)+」一样。正确的办法是,去掉表示占有优先的加号,用固化分组把余下的部分包括起来:

(?>("|[^"])*)

  上面的过程可以使用下面的代码验证:

publicstaticvoidmain(String[]args)
{
String[]datas={"1.234001","1.234","1.230","1.23"};
Patternpattern=Pattern.compile("(.dd[1-9]?)d*");
for(Stringdata:datas)
{
Matchermatcher=pattern.matcher(data);
if(matcher.find())
{
System.out.println(matcher.group(1));
}
else
{
System.out.println("不匹配");
}
}

System.out.println("========");

pattern=Pattern.compile("(.dd[1-9]?)d+");
for(Stringdata:datas)
{
Matchermatcher=pattern.matcher(data);
if(matcher.find())
{
System.out.println(matcher.group(1));
}
else
{
System.out.println("不匹配");
}
}

System.out.println("========");

pattern=Pattern.compile("(.dd(?>[1-9]?))d+");
for(Stringdata:datas)
{
Matchermatcher=pattern.matcher(data);
if(matcher.find())
{
System.out.println(matcher.group(1));
}
else
{
System.out.println("不匹配");
}
}

System.out.println("========");

pattern=Pattern.compile("(.dd(?>[1-9]?+))d+");
for(Stringdata:datas)
{
Matchermatcher=pattern.matcher(data);
if(matcher.find())
{
System.out.println(matcher.group(1));
}
else
{
System.out.println("不匹配");
}
}
}

输出

.234
.234
.23
.23
========
.234
.23
.23
不匹配
========
.234
不匹配
.23
不匹配
========
.234
不匹配
.23
不匹配


其他参考资料

《[精华] 正则表达式30分钟入门教程》

http://www.oschina.net/question/12_9507


《千里之行始于足下》的博客

http://www.52php.cn/cata/106952


《雁过无痕》的博客

http://www.52php.cn/cata/402158

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读