Java基础之 浅谈正则表达式

  • Post author:
  • Post category:java


正则表达式在各种编程语言中几乎都有,其存在的最大意义是方面用户处理文本信息。比如:在一篇文章中查询其数字或者某写字段。

各自的语言在通过正则进行匹配的时候调用有所不同,但是其正则表达式本身区别不到。而本篇主要讲解分两部分

Java正则调用底层是什么



正则表达式的格式



java中正则

文本的处理任何语言都无法避免的一种操作,这个一段先不讲解正则表达式的格式或者写法,而是了解java是如何调用正则。

老规矩先看调用代码。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class test {
	public static void main(String[] args) {

		String txt="汇编语言, 即第二代计算机语言,用一些容易理解和记忆的字母,"
				+ "单词来代替一个特定的指令,比如:用“ADD”代表数字逻辑上的加减,"
				+ "“ MOV”代表数据传递等等,通过这种方法,人们很容易去阅读已经完成的程序或者理解程"
				+ "序正在执行的功能,对现有程序的bug修复以及运营维护都变得更加简单方便。但计"
				+ "算机的硬件不认识字母符号,这时候就需要一个专门的程序把这些字符变成计算"
				+ "机能够识别的二进制数。因为汇编语言只是将机器语言做了简单编译,所以并没有"
				+ "根本上解决机器语言的特定性,所以汇编语言和机器自身的编程环境息息相关"
				+ ",推广和移植很难,但是还是保持了机器语言优秀的执行效率,因为他的可阅读"
				+ "性和简便性,汇编语言到现在依然是常用的编程语言之一。 汇编语言不像其他大多数的程序"
				+ "设计语言一样被广泛用于程序设计。在今天的实际应用中,"
				+ "它通常被应用在底层,硬件操作和高要求的程序优化的场合。"
				+ "驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言。";


       String rex="[A-Z,a-z]";// 表达式的意思就是查询字符串中还有的单个字母
       Pattern pattern= Pattern.compile(rex);
       Matcher matcher=pattern.matcher(txt);
       while(matcher.find()) {
    	   
    	   System.out.println(matcher.group(0));
       }
    }
}
// 输出
A
D
D
M
O
V
b
u
g

对于上面代码其实可以看出在java.util.regex下的两个主要的类Pattern,Matcher。简单的调用,根据上面的方法即可得知,但是有一个地方可能会有人注意到:

matcher.group(0)

。为什么我们取出的数据都是坐标为0.

在这里插入图片描述

在这里插入图片描述

通过图可以看出group数组中的下标二1的减去下标为0的总是等于

汇编语言

的长度:4

可以得出一个结论那就是group 这个数组,会存储查找到的数据的起始和结束坐标,然后没查找一个就会变一此。但是每次都是数组前两个变。

  • 这个就有疑问了,明明是数组中的两个数,为什么group(0)?
    public String group(int group) {
        if (first < 0)
            throw new IllegalStateException("No match found");
        if (group < 0 || group > groupCount())
            throw new IndexOutOfBoundsException("No group " + group);
        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
            return null;
        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
    }

源码可以得出,人家自己乘以2进行了一次运算了,所以

而getSubSequence 调用的的SubSequence方法,与字符串中的substring效果一样。

  • 疑问2:如果group(0),直接定义长度为2的数组即可,干嘛还要创建要给大于2的数组呢?

    其实这个有涉及到正则表达式中的捕获组的表达方式了。(先记住,后面聊)

在这里插入图片描述

这个可以看出来一点,那就是groups数组中给下标2,3代表都是是前面的小括号内容,下标4,5代表的是后面的小括号内容。而0,1代表是整体的内容。

现在再看group(int group) ,就明白group(1)和group(1)代表的内容了。



正则表达式

对于正则表达式有时候看着会觉得凌乱,其实不然,这个需要一种方式多用加强记忆,而主要记的就是其不同的符号代表的意思。

而根据不同的功能,元字符功能大致分:

  • 限定符
  • 选择匹配符
  • 分组组合和反向引用符
  • 特殊字符
  • 字符匹配符
  • 定位符

而这一篇将其放入java,那就是以Java作为基础进行演示,不过正则表达式规则,虽各个语言各有差异但有大体相同。



转义符

为什么要有转义符,因为有些特殊符号在正则表达式中有不同的涵义,但是有时候需要使用其本来字符代表的字符串意思。

比如 (

\

),需要找找是否有这个符号,发现Java编译都编译不过去,有时候编译过去了,但是无法查询自己需要的字符串。所以需要转移符号写(

\\

),这样前面加一个反斜杠,其代表就是转移。

**注意:**而再java中的正则表达式转义符是 (\\) 等于其他语言的中的一个(\)

需要用到转义符号的字符:

. * + (
) $ / \
? [ ] ^
{
}



字符匹配符

符号 作用 示例 解释
[ ] 可接受的字符列表 [abcd] 选取abcd中的任意一个字符,不要看成一个连续abcd。
[ ^] 不可接受的字符列表 [^abcd] 除去abcd之外的任意一个字符。
连接符 a-z 任意一个小写字母
. 匹配除了\n以外任何一个字符 a…b 以a开头,以b结尾,中间有两个除\n以外的字符(因为前面写了两个 . )a±b,abgb等
\\d 匹配单个数字的字符,相当于[0-9] \\d 可以得到任何单个数字,比如0,1,9等单个数字,不过一般会搭配限定符一起用
\\D 匹配单个非数字字符,相当于[^0-9] \\D 可以得到任何除了数字的字符,比如:A,a,+,%等。不过一般也会跟着限定符一起用。
\w 匹配单个数字,大小写字符,相当于[0-9a-zA-Z] \w 可以得到数字,大小写字符的,比如:A,a,1,等。不过一般也会跟着限定符一起用。
\W 匹配单个非数字,大小写字符,相当于[^0-9a-zA-Z] \W 可以得到除了数字,大小写字符的,比如:%,+,-,等。不过一般也会跟着限定符一起用。
String str="a2b+3cdABC#我";
String rex="这个根据要求在现在写";
 Pattern pattern= Pattern.compile(rex);
 Matcher matcher=pattern.matcher(txt);
  while(matcher.find()) {
     System.out.println(matcher.group(0));
  }

#  匹配字符串中小写字符。
    rex="[a-z]";
    因为可以看出其小写只有abcd 也可以写:rex="[abcd]";不过一般除非定义匹配这四个字符,不然一般执行写a-z
   输出:
       a
       b
       c
       d

# 匹配字符串中的数字
   rex="[0-9]";
   或者: rex="\\d";
        
   输出:
        2
        3
# 匹配字符串中的非数字,大小写字母的字符
   rex="{\\W}";
   或者: rex="[^0-9A-Za-z]";
        
   输出:
        +
        #
        我



限定符

用于指定前面的字符和组合项目连续出现的次数。

符号 含义 示例 说明
* 指定字符重复0次或n次 hg(abc)* 会匹配hg,hgabc 或者hg ,abcabc等字符串,
+ 指定字符重复1次或n次(要求必须出现一次) hg(abc)+ 会匹配hgabc 或者abcabc等字符串,
? 指定字符重复出现0次或者1次 hg(abc)? 会匹配hgabc 或者hg 这两种字符串
{ n } 指定字符串重复出现n次 hg(abc){2} 会匹配bgabcabc 这个样子的字符串
{n,} 指定至少n个匹配 [abc]{2,} 会匹配aa,aba,aaaa,ac,ca,等字符串能长度低于2
{n,m} 指定至少n个但是不多与m个匹配 [abc]{2,3} 会匹配 ac ,aac,ccc等字符串不能长度超过3,低于2
| 选择匹配符 hg|abc 会匹配hg或者abc的字符串
String str="abc45abcbc++a";
String rex="这个根据要求在现在写";
 Pattern pattern= Pattern.compile(rex);
 Matcher matcher=pattern.matcher(txt);
  while(matcher.find()) {
     System.out.println(matcher.group(0));
  }

## 匹配a如果a字母后面有bc的话无论重复几次bc也需要匹配
    rex="a(bc)*";
输出:
    abc
    abcbc
    a

##匹配bc的字符前面有a的字符,无论出现多少次bc
    rex="a(bc)+";
  输出
      abc
      abcbc
      
## 匹配a以及a后面有一次bc的字符串
      rex="a(bc)?";或者 rex="a|abc";
 输出:
     abc
     abc
     a
## 匹配abcbc文件
     rex="a(bc){2}"; 或者 rex="abcbc";
 输出:
     abcbc

## 匹配字母长度连续大于2,小于4的字符串
     rex=[a-z]{2,4};
   输出:
       abc
       abcb
       



分组

这个前面用到了多次,那就是一对()

格式 说明
(pattern) 非命名捕获,捕获匹配的子字符串。编号为零的第一个捕获的由整个正则表达式模式匹配的文本,其他的捕获结果则根据左右括号的顺序从1开始自动编号。(具体理解,可以看java正则的截图)
(?<name> pattern) 命名捕获,捕获匹配的子字符串,以及给其一个组名或编号的名称中。用与name的字符串不能包含任何标点符号,并且不能以数字开头,额可以使用单引号代替尖括号,例如(?‘name’)
(?:pattern) 特殊的分组,匹配pattern但不捕获该匹配的子表达式,即他是一个非捕获的匹配,不存储供以后使用的匹配。这个对于用“or”字符(|)组合模式部件的情况很有用sb(?:ni|ta)比表达式 sbni|sbta一样,如果使用group(1) 会报错没有这个值。 如果写成sb(ni|ta),那么就可以用group(1)可以取数据了。
(?=pattern) 特殊分组,是一个非捕获的匹配。比如sb(?=ni) 如果sb后面是ni那么就会取出sb,如果sb后面是除了ni以外比如ta就不会取出。注意:只会匹配得到sb而不是sbni,同意group(1)也是没有数据的。
(?!pattern) 特殊分组,是一个非捕获的匹配,和(?=pattern)相反。比如sb(?!ni) 如果sb后面是ni那么就不会会取出sb,如果sb后面是除了ni以外比如ta就会取出。注意:只会匹配得到sb而不是sbta,同意group(1)也是没有数据的。
		String txt="汇编语言, 即第二代计算机语言,用一些容易理解和记忆的字母,"
				+ "单词来代替一个特定的指令,比如:用“ABCDEFGHIJK”代表数字逻辑上的加减,"
				+ "“ MOV”代表数据传递等等,通过这种方法,人们很容易去阅读已经完成的程序或者理解程"
				+ "序正在执行的功能,对现有程序的bug修复以及运营维护都变得更加简单方便。但计"
				+ "算机的硬件不认识字母符号,这时候就需要一个专门的程序把这些字符变成计算"
				+ "机能够识别的二进制数。因为汇编语言只是将机器语言做了简单编译,所以并没有"
				+ "根本上解决机器语言的特定性,所以汇编语言和机器自身的编程环境息息相关"
				+ ",推广和移植很难,但是还是保持了机器语言优秀的执行效率,因为他的可阅读"
				+ "性和简便性,汇编语言到现在依然是常用的编程语言之一。 汇编语言不像其他大多数的程序"
				+ "设计语言一样被广泛用于程序设计。在今天的实际应用中,"
				+ "它通常被应用在底层,硬件操作和高要求的程序优化的场合。"
				+ "驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言。";

       String rex="(?<name1>汇编)(?<name2>语言)";
       Pattern pattern= Pattern.compile(rex);
       Matcher matcher=pattern.matcher(txt);
       while(matcher.find()) {

    	   System.out.println("=====全部"+matcher.group(0));
    	   System.out.println("=====0"+matcher.group(1));
    	   System.out.println("=====0"+matcher.group("name1"));
    	   System.out.println("=====1"+matcher.group(2));
    	   System.out.println("=====1"+matcher.group("name2"));
       }

//输出
=====全部:汇编语言
=====0:汇编
=====0:汇编
=====1:语言
=====1:语言
......
=====全部:汇编语言
=====0:汇编
=====0:汇编
=====1:语言
=====1:语言   



定位符

定位符规定要匹配的字符串出现的位置,比如在字符串的开始还是结束,这个也是很常用的功能,比如匹配邮箱或者url地址等。

符号 含义 示例 说明
^ 指定起始字符(和[^]代表的意思不一样,不要记错) ^[1,3]+[a-z]* 至少1个数字开头,后面有任意小写字母。例如:13adf,2fgf等
$ 指定结束字符 ^[1,3]+\\*$ 至少1个数字开头,但是最后一位必须是*结尾
\\b 匹配目标字符串的边界 sb\\b 字符串的边界指的是子串间有空格,或者是目标字符串的结束位置,比如:sbdf

sb

sbdfd

sb
\\B 与\\b刚刚相反 sb\\B
sb

dfsb sbdfdsb



补充

正则表达式在匹配的时候有两个模式:

贪婪匹配



非贪婪匹配

  • 贪婪匹配:那就是在匹配的时候,尽可能的长的数据。比如使用:{n,m},+,?,*

    在使用中,尽可能匹配最长的字符串。

    		txt="123WER13445+df13";
    
    		String rex="\\d{2,5}";// 匹配长度为2到5个数字的字符串
    
           Pattern pattern= Pattern.compile(rex);
           Matcher matcher=pattern.matcher(txt);
    
           while(matcher.find()) {
        	   System.out.println("=====全部:"+matcher.group(0));
    
           }
    //输出
    =====全部:123
    =====全部:13445
    =====全部:13
    

    可以看出其匹配。尽可能的长。

  • 非贪婪匹配:这种匹配的时候如果以满足匹配,就不会在继续让其变的更长。比如在{n,m},+,*后面添加一个?,看下面代码演示:


	   txt="123WER13445+df13";

		String rex="\\d{2,5}?";// 匹配长度为2到5个数字的字符串

       Pattern pattern= Pattern.compile(rex);
       Matcher matcher=pattern.matcher(txt);

       while(matcher.find()) {
    	   System.out.println("=====全部:"+matcher.group(0));

       }
//输出
=====全部:12
=====全部:13
=====全部:13



版权声明:本文为u011863822原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。