JAVA笔记之正则表达式

原文地址:https://zhuanlan.zhihu.com/p/59904349

字符匹配符与范围控制符

  1. . (点) 任意字符
  2. \s (反斜杠加小写字母s) 空白字符: 回车,制表,空格,换行
  3. \S (反斜杠加大写字母S) 非空白字符, 除了上面那四个空白字符
  4. \w (反斜杠加小写字母w) 单词字符: 小写字母a-z, 大写字母A-Z, 数字0-9, 下划线 _
  5. \W (反斜杠加大写字母W) 非单词字符,除了上面提到的那些单词字符
  6. [ ] (中括号) 范围字符
    1. [abc] 表示字母abc中的任意一个
    2. [a-z] 表示字母a到z中的任意一个
    3. [^abc] ^ 为取非, 除了abc, 剩下的全部字符
    4. [abc[def]] 这种写法为并集,意为abcdef中的任意一个
    5. [abc&[bce]] & 表示, 也就是交集。 abc 与上 bce, 最终结果为bc

 

数量控制符

上面介绍的字符匹配符和范围控制符,一般是与数量控制符组合使用,才能发挥真正威力。 而数量控制符号,分为贪婪型,勉强型,和占有型三种类型,每种类型在不同的场合有不同的用法。

贪婪型

  1. ? 表示1个或0个。换句话说,表示要不然没有,要不然只有1个
  2. * 表示0个或多个。
  3. + 表示1个或多个。
  4. {n} 表示正好n个
  5. {n,m} 表示n到m个,这是一个左闭右闭区间
  6. {n,} 表示至少n个

 

勉强型

相比于贪婪型,勉强型只是多了一个?:

 

  1. ?? 表示1个或0个。换句话说,表示要不然没有,要不然只有1个
  2. *? 表示0个或多个。
  3. +? 表示1个或多个。
  4. {n}? 表示正好n个
  5. {n,m}? 表示n到m个,这是一个左闭右闭区间
  6. {n,}? 表示至少n个

占有型

相比于贪婪型,占有型多了一个 +

 

  1. ?+ 表示1个或0个。换句话说,表示要不然没有,要不然只有1个
  2. *+ 表示0个或多个。
  3. ++ 表示1个或多个。
  4. {n}+ 表示正好n个
  5. {n,m}+ 表示n到m个,这是一个左闭右闭区间
  6. {n,}+ 表示至少n个

不同类型的区别

现在详细分析 贪婪型、勉强型和占有型的区别, 举例如下:

        String s = "abcd&"; 			// 目标字符串
        String regular = "\\w+\\w";		// 贪婪型正则
		String regular2 = "\\w+?\\w";		// 勉强型正则
		String regular3 = "\\w++\\w";		// 占有型正则
        Matcher m = Pattern.compile(regular).matcher(s);
		// 调用方法去匹配字符串
        if(m.find()) {
		   System.out.println(m.group());
		}

分析:

  1. 贪婪型。\w+, 意为匹配一个或多个单词字符,对于贪婪型,将尽量多的匹配字符,abcd全部匹配出来,直到遇到特殊字符&,匹配结束,然后用\w 去匹配特殊字符&,发现并不匹配,此时将会回溯,也就是说\w+只匹配abc三位,然后让最后一个\w去匹配d,最终\\w+\\w匹配出结果abcd.
  2. 勉强型。对于勉强型,会尽量少的匹配字符。既然,+表示一个或多个,那就只匹配一个,所以\w+?最终只匹配出一个a, 然后\w再去匹配一个b,最终匹配结果为ab。
  3. 占有型。 占有型和贪婪型很像,刚开始也会尽量多的匹配字符,但是占有型没有回溯机制,遇到不匹配的内容后,将自动停止而不是向前回溯。 所以 \\w++,自动匹配到abcd之后,遇到了&,发现不匹配,然后自动停止了,此时还有一个\w也和&不匹配,所以最终结果匹配失败,输出为空。

位置匹配符

位置匹配符,不匹配任何字符只匹配位置。也就是说,位置匹配符是零宽度的,只匹配位置。

  1. ^ 匹配一行的开始位置
  2. $ 匹配一行的结束位置
  3. \b 匹配单词边界。 这里的单词指的就是, a-z, 0-9, _, 和\w不同的是,\b匹配的单词还包括汉字。 单词边界匹配,是匹配单词字符和非单词字符之间的位置。
  4. \B 匹配非单词边界。和\b,刚好相反, \B 匹配单词与单词之间的位置,或者非单词与非单词之间的位置。
  5. \G 匹配前一个匹配结束时的位置。

 

举例说明:

String s = "a=124_a=789_a=490"; 	
String regular = "^a=\\d+";

比如说只想把开头的a=124找出来,而不关心后面的a,此时就可以用位置匹配符。^匹配一行的开始位置,a= 去匹配 a=, \\d+匹配出124, 所以最终可正确匹配出开始位置的a=124

 

还有一类特殊的匹配符,虽然严格意义上来说不能算是位置匹配符,但是由于这类匹配符也是零宽度的,所以本文章把这类匹配符归为位置匹配符。 这类特殊的匹配符,称为零宽度断言匹配

  1. (?=exp) 零宽度向前匹配
  2. (?<=exp) 零宽度向后匹配
  3. (?!exp) 零宽度向前非匹配
  4. (?<!exp) 零宽度向后非匹配

举例说明2:

// 目标字符串。 只想取出2前面的abc
                String s = "abc1 abc1 abc2 abc3";
                String regular = "\\w{3}(?=2)";
		Matcher m = Pattern.compile(regular).matcher(s);
                while(m.find()) {
                   System.out.println(m.group());
		}

 

就像是$匹配字符串结尾一样,(?=2) 也是匹配字符串中为2的位置,然后再去检查(?=2)前面的\\w{3} 是否匹配abc, 匹配则输出结果。 之所以说是零宽度,是因为(?=2)只是起一个锚点定位作用,此时尾指针指向的不是2后面,而是c后面。

再比如说3:

String s = "aaaaaaaa";
                String regular = "aa(?=aa)";
		Matcher m = Pattern.compile(regular).matcher(s);
                while(m.find()) {
	            System.out.println(m.group());
		}

结果输出将是: aa aa aa

因为,第1次匹配,匹配到前4个a,输出aa; 第2次匹配,是从第2个a后开始向后,而不是第4个a后面,(?=aa) 只标定位置,不占有宽度; 以此类推,最终结果输出为aa aa aa

举例说明4:

对于零宽度向前匹配,和向后匹配方向相反:

// 目标字符串。 只要求输出2后面的abc
                String s = "1abc 2abc 3abc";
                String regular = "(?<=2)\\w{3}";
		Matcher m = Pattern.compile(regular).matcher(s);
                while(m.find()) {
			System.out.println(m.group());
		}

 

只要求输出2后面的abc,那么就可以用(?<=2)来进行锚点标定,匹配出其后面的字符串。

 

对于(?!exp) 和 (?<!exp) 这两个非匹配断言,和匹配断言正好相反。 (?!exp) 是要求匹配内容的后面,不能有指定的内容; (?<!exp) 要求匹配的前面不能有指定的内容。

 

模式说明符

  1. (?i) 开启大小写忽略模式,但是只适用于ASCII字符
  2. (?u) 开启utf-8编码模式
  3. (?m) 开启多行匹配模式,.不匹配空白字符
  4. (?s) 单行模式,.匹配任意字符,包括空白字符
  5. (?d) 单行模式,.不匹配空白字符

 

举例说明:

String test2 = "I care not whether I can succeed\n"
		+ "Since in choice of the distance\n"
		+ "I simply travel in wind and rain\n"
		+ "I care not whether I can win love\n"
		+ "Since in deep love with a rose\n"
		+ "I just unbosom myself bravely"; 
String reg = "(?m)\\w{3}$";

在默认情况下,^ 和 $ 只匹配全部字符串的开始与结束位置,但是如果用(?m)开启多行匹配模式之后, ^ 和 $ 将匹配每一行的开始与结束位置。所以说,上面上面那个举例正则(?m)\\w{3}$,将会匹配出每一行的最后三个字符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值