Java正则匹配

在Java中使用原生JDK实现正则表达式的匹配,不可避免的我们需要使用到java.util.regex包下的两个类PatternMatcher

初识模式匹配

我们的一般用法,就是先定义一个正则串匹配串,然后看匹配串中是否有满足正则串条件的字符序列;如下:

 

java

代码解读

复制代码

public class Demo1 { public static void main(String[] args) { //[a-z]表示a~z之间的任何一个字符, {3}表示3个字符, 意思是匹配一个长度为3, 并且每个字符属于a~z的字符串 Pattern p = Pattern.compile("[a-z]{3}"); Matcher m = p.matcher("abc"); System.out.println(m.matches()); } } //输出结果 true

  • 如果要深究正则表达式背后的原理, 会涉及编译原理中自动机等知识, 此处不展开描述. 为了达到通俗易懂, 这里用较为形象的语言描述.

  • Pattern可以理解为一个模式, 字符串需要与某种模式进行匹配. 比如Demo2中, 我们定义的模式是一个长度为3的字符串, 其中每个字符必须是a~z中的一个.

  • 我们看到创建Pattern对象时调用的是Pattern类中的compile方法, 也就是说对我们传入的正则表达式编译后得到一个模式对象. 而这个经过编译后模式对象, 会使得正则表达式使用效率会大大提高, 并且作为一个常量, 它可以安全地供多个线程并发使用.

  • Matcher可以理解为模式匹配某个字符串后产生的结果. 字符串和某个模式匹配后可能会产生很多个结果, 这个会在后面的例子中讲解.

  • 最后当我们调用m.matches()时就会返回完整字符串与模式匹配的结果

  • 上面的三行代码可以简化为一行代码 System.out.println("abc".matches("[a-z]{3}"));

  • 但是如果一个正则表达式需要被重复匹配, 这种写法效率较低.

完全匹配和部分匹配

通过上面的Demo1样例中,我们以经初步了解了Java对正则表达式匹配的简单使用;我们再来看下面这个Demo2样例

 

java

代码解读

复制代码

public class Demo2 { public static void main(String[] args) { //[a-z]表示a~z之间的任何一个字符, {3}表示3个字符, 意思是匹配一个长度为3, 并且每个字符属于a~z的字符串 Pattern p = Pattern.compile("[a-z]{3}"); // 正则串 - "[a-z]{3}" Matcher m = p.matcher("abcd"); // 模式串 - "abcd" System.out.println(m.matches()); } }

大家可以猜测这个结果会输出什么呢?此处停留3秒~~~

大家可以复制这段代码运行一遍,会惊奇的发现,现在输出的结果变为了false而不再是原来的true了;

为什么出现上面这个情况呢?我们仅仅是在匹配串里面多加了一个d字符,为什么就会导致匹配不上了呢?

要回答上面的问题,就需要了解完全匹配和部分匹配的区别;

  • 完全匹配整个匹配串全都匹配正则串
  • 部分匹配匹配串有子串匹配正则串

使用Matcher.matches()方法判断匹配串是否匹配到正则串是一种完全匹配的判断,即需要完全匹配的情况下才会返回true;而如果我们想如果部分匹配到了就返回true,我们就需要使用Matcher.find()来判断是否部分匹配到结果

整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

java

代码解读

复制代码

public class Demo3 { public static void main(String[] args) { //[a-z]表示a~z之间的任何一个字符, {3}表示3个字符, 意思是匹配一个长度为3, 并且每个字符属于a~z的字符串 Pattern p = Pattern.compile("[a-z]{3}"); // 正则串 - "[a-z]{3}" Matcher m = p.matcher("abcd"); // 模式串 - "abcd" System.out.println(m.find()); } }

执行Demo3样例会发现现在打印出的结果过即是true

起始/终止标识符

 

java

代码解读

复制代码

public class Demo4 { public static void main(String[] args) { //[a-z]表示a~z之间的任何一个字符, {3}表示3个字符, 意思是匹配一个长度为3, 并且每个字符属于a~z的字符串 Pattern p = Pattern.compile("^[a-z]{3}$"); // 正则串 - "^[a-z]{3}$" Matcher m = p.matcher("abcd"); // 模式串 - "abcd" System.out.println(m.find()); } }

执行Demo4样例会发现现在打印出的结果又变为了false

这是因为我们在正则串-^[a-z]{3}$的前后加入了起始^/终止$标识符;等价于要全匹配,才能返回true

我们改为Demo5样例,执行

 

java

代码解读

复制代码

public class Demo5 { public static void main(String[] args) { //[a-z]表示a~z之间的任何一个字符, {3}表示3个字符, 意思是匹配一个长度为3, 并且每个字符属于a~z的字符串 Pattern p = Pattern.compile("^[a-z]{3}$"); // 正则串 - "^[a-z]{3}$" Matcher m = p.matcher("abc"); // 模式串 - "abcd" System.out.println(m.find()); } }

会发现现在的结果又变为了true,因为现在是匹配串正则串完全匹配

分组匹配

以下是一段Cisco防火墙的配置

 

tex

代码解读

复制代码

...... access-list 1 line 2 extended permit object TCP-33 object-group oa-ip object-group oa-test (hitcnt=0) 0x8f05ca88 access-list 1 line 2 extended permit tcp host 10.1.1.4 host 20.1.1.1 range 33 33 (hitcnt=0) 0xa1bf013a access-list 1 line 2 extended permit tcp host 10.1.1.4 host 20.1.1.5 range 33 33 (hitcnt=0) 0x3372620c access-list 1 line 2 extended permit tcp host 10.1.1.5 host 20.1.1.1 range 33 33 (hitcnt=0) 0xf907dcff access-list 1 line 2 extended permit tcp host 10.1.1.5 host 20.1.1.5 range 33 33 (hitcnt=0) 0x73b10004 access-list 1 line 2 extended permit tcp host 10.1.1.1 host 20.1.1.1 range 33 33 (hitcnt=0) 0x964c8122 access-list 1 line 2 extended permit tcp host 10.1.1.1 host 20.1.1.5 range 33 33 (hitcnt=0) 0xf6fd9fc9 access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32 (hitcnt=0) (inactive) 0xb206976e access-list 1 line 3 extended permit tcp host 172.21.2.10 host 11.1.1.10 range 33333 33333 (hitcnt=0) 0xb206976e access-list 2; 1 elements; name hash: 0x4ba440f6 access-list 2 line 1 extended permit ip any any (hitcnt=0) 0x86268c7e ......

假设我们现在要查找其中access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32 (hitcnt=0) 0xb206976e 策略的HASH值0xb206976e

 

java

代码解读

复制代码

public void groutMatch() throws IOException { String raw = "上面Cisco防火墙的配置" String policy = "access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32"; // 转换特殊字符`.` String replacedPolicy = policy.replaceAll("\\.", "\\\\."); // 全匹配 // String policyTemp = "^[\\s\\S]*?(policy)(\\s*?)(\\(\\S*?\\)\\s)(\\(\\S*?\\)\\s)*?(0x\\S+)[\\s\\S]*$"; // 部分匹配 String policyTemp = "(policy)(\\s*?)(\\(\\S*?\\)\\s)(\\(\\S*?\\)\\s)*?(0x\\S+)"; policyTemp = policyTemp.replace("policy", replacedPolicy); Pattern CISCO_REGEX = Pattern.compile(policyTemp); Matcher matcher = CISCO_REGEX.matcher(raw); if (matcher.find()) { // matcher.group(index) System.out.print(matcher.group(1)); System.out.print(matcher.group(2)); System.out.print(matcher.group(3)); System.out.print(StringUtils.isBlank(matcher.group(4))? "" : matcher.group(4)); System.out.println(matcher.group(5)); } else { System.out.println("not match"); } }

matcher.group(index)其中group是针对括号()来说的,group(0)就是指的整个串,group(1) 指的是第一个括号里的东西,group(2)指的第二个括号里的东西。

对应上面的样例,我们可以拆解为如下:

image.png

***注意:***这里我们可以发现第3个括号中的正则表达式和第4个括号正则表达式的内容是一样的;理论上我们可以不要第3个括号的正则表达式因为第4个括号正则表达式后面跟随了*?可以匹配0-N个相同的正则表达式内容;但是由于当有多匹配*/+的时候,通过group(index)获取匹配内容的时候只能拿到最后一个匹配的内容;但是group(0)还是可以拿到匹配的所有内容

 

java

代码解读

复制代码

public void groutMatch() throws IOException { String raw = "上面Cisco防火墙的配置" String policy = "access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32"; // 转换特殊字符`.` String replacedPolicy = policy.replaceAll("\\.", "\\\\."); // 部分匹配 String policyTemp = "(policy)(\s*?)(\(\S*?\)\s)*?(0x\S+)"; policyTemp = policyTemp.replace("policy", replacedPolicy); Pattern CISCO_REGEX = Pattern.compile(policyTemp); Matcher matcher = CISCO_REGEX.matcher(raw); if (matcher.find()) { // matcher.group(index) System.out.print(matcher.group(1)); System.out.print(matcher.group(2)); System.out.print(matcher.group(3)); System.out.print(StringUtils.isBlank(matcher.group(4))? "" : matcher.group(4)); System.out.println(); System.out.println(matcher.group(0)); } else { System.out.println("not match"); } }

输出如下结果:

access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32 (inactive) 0xb206976e

matcher.group(0)的输出结果

access-list 1 line 3 extended permit object TCP-33333 object WS-172.21.2.10_32 object WS-11.1.1.10_32 (hitcnt=0) (inactive) 0xb206976e

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值