Java正则表达式

java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。它包括两个类:PatternMatcher。Pattern是一个正则表达式经编译后的表现模式。Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。 首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。

正则表达式的构造摘要

详细摘要请看jdk中文文档,下面我只是列出一些经常使用的

构造 匹配
. 任何字符(与行结束符可能匹配也可能不匹配)
d 数字:[0-9]
D 非数字: 1
s 空白字符:[ tnx0Bfr]
S 非空白字符:2
w 单词字符:[a-zA-Z_0-9]
W 非单词字符:3
[abc] a、b 或 c(简单类)
4 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
^ 行的开头
$ 行的结尾
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次

Pattern

正则表达式的编译表示形式,学过python的都知道这个和python的正则表达式有异曲同工之妙。 但是它的构造方法是私有的,因此不能直接创建对象,但是可以调用它的静态方法返回一个对象,下面会详细介绍

创建对象

  • Pattern类用于创建一个正则表达式,也可以说创建一个匹配模式,它的构造方法是私有的,不可以直接创建,但可以通过Pattern.complie(String regex)简单工厂方法创建一个正则表达式,代码如下:

    //采用的complie(String regex)
    Pattern pattern = Pattern.compile("\\d+");
    
    //采用的是complie(String regex,int flag)其中flag表示标志,下面的标志表示忽略字母大小写,详细的字段请看文档
    Pattern pattern=Pattern.compile("(CHEN)(\\D*)(\\d*)",Pattern.CASE_INSENSITIVE);

常用方法

  • Pattern compile(String regex) 用于创建Pattern对象

  • Pattern compile(String regex,int flags) 用于创建Pattern对象,并且指定了标志(比如忽略字母大小写)

  • int flags() 返回此模式的匹配标志

  • String pattern() 返回在其中编译过此模式的正则表达式。

  • String[] split(CharSequence input) 根据此模式的正则表达式将输入的字符串拆分成String数组,默认的都是全部拆分开

    //给出正则表达式用于匹配数字(0-9)
    Pattern pattern = Pattern.compile("\\d+");
    String str = "我是陈加兵456郑元梅34擦市场的逻辑啊";
    String[] splits = pattern.split(str, 2);   //结果:[我是陈加兵,郑元梅34擦市场的逻辑啊]
  • String[] split(CharSequence input,int limit) 将字符串按照正则表达式表示的内容进行分组,如果limit>0那么就分成limit个组,如果limit<0就按照默认全部分开

    //给出正则表达式用于匹配数字(0-9)
    Pattern pattern = Pattern.compile("\\d+");
    String str = "我是陈加兵456郑元梅34擦市场的逻辑啊";
    String[] splits = pattern.split(str, 2);   //结果:[我是陈加兵,郑元梅34擦市场的逻辑啊]
  • Pattern.matches(String regex,CharSequence input)是一个静态方法,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串

    Pattern.matches("\\d+","2223");//返回true 
    Pattern.matches("\\d+","2223aa");//返回false,需要匹配到所有字符串才能返回true,这里aa不能匹配到 
    Pattern.matches("\\d+","22bb23");//返回false,需要匹配到所有字符串才能返回true,这里bb不能匹配到 
  • Matcher matcher(CharSequence input) 创建匹配给定输入与此模式的匹配器,现在只是先了解以下,下面会详细解释Matcher这个类

    Pattern p=Pattern.compile("\\d+"); 
    Matcher m=p.matcher("22bb23"); 

Matcher

Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.
Matcher类和Pattern类一样它的构造方法同样是私有的,因此不能直接构造对象,但是上面我们说过Pattern类中有一个方法可以返回一个Matcher对象(matcher(CharSequence input))

常用的方法

  • boolean mathces() 尝试将整个区域与模式匹配(针对的是整个字符串,如果整个字符串未完全匹配,那么返回false,如果完全匹配那么返回true)

        Pattern pattern=Pattern.compile("\\d+");  //创建Pattern对象
        String str="I am hreo 1234";  //需要匹配的字符串
        Matcher matcher=pattern.matcher(str);
        //并没有完全匹配,因此返回false,如果str="123445",那么就会返回true
        System.out.println(matcher.matches());  
  • boolean lookingAt() 尝试从给定字符串的开头开始匹配,如果有子字符串匹配成功,那么返回true(针对的不是整个字符串,而是从开头开始,如果开头有一段字符串匹配成功,那么返回true)

        Pattern pattern=Pattern.compile("\\d+");  //创建Pattern对象
        String str="1234 I am a hero";  //需要匹配的字符串
        Matcher matcher=pattern.matcher(str);
        //开头的1234匹配到了,因此返回true,如果str="I am a hero  1234"将返回false
        System.out.println(matcher.lookingAt());
  • int start() 匹配到的字符串的第一个元素的索引,如果没有匹配到调用此方法将会报错

  • int end() 匹配到的字符串的最后一个元素的索引,如果没有匹配到调用此方法将会报错

  • String group() 返回的是匹配到的字符串,如果没有匹配到调用此方法将会报错

        Pattern pattern=Pattern.compile("\\d+");  //创建Pattern对象
        String str="1234 I am a hero 33455";  //需要匹配的字符串
        Matcher matcher=pattern.matcher(str);
        if(matcher.lookingAt())
        {
            System.out.println("开始匹配到下标为"+matcher.start());  //0
            System.out.println("匹配结束的下标为"+matcher.end());    //4
            System.out.println("匹配的字符串为"+matcher.group());  //1234
        }
  • boolean find() 查找整个字符串,如果在任意位置有一段字符串能够匹配成功,那么返回true(任意位置),然后如果再次调用这个查找的话,那么就从上次查找到的末尾开始匹配,也就是说查找的是下一个子序列了

        Pattern pattern=Pattern.compile("\\d+");  //创建Pattern对象
        String str="1234 I am a hero 6666 chenjiabing8888";  //需要匹配的字符串
        Matcher matcher=pattern.matcher(str);
        while(matcher.find())  //如果还有匹配的字符序列
        {
            System.out.println("开始匹配到下标为"+matcher.start()); 
            System.out.println("匹配结束的下标为"+matcher.end());   
            System.out.println("匹配的字符串为"+matcher.group());  
        }  
        
    /*结果如下:
     * 
    开始匹配到下标为0
    匹配结束的下标为4
    匹配的字符串为1234
    开始匹配到下标为17
    匹配结束的下标为21
    匹配的字符串为6666
    开始匹配到下标为33
    匹配结束的下标为37
    匹配的字符串为8888
    */
    
    /*
     * 从上面返回的结果可以知道,find()可以匹配多次只要这个字符串还有可以匹配,
     * 并且每次的匹配字段的开始下标都是上一次匹配的结束字母的下一个下标
     */
  • boolean find(int start) 从指定的索引start位置开始匹配,这个用于重置find()匹配器,因为直接使用find()它的每次开始的索引都是不一样的

  • String group(int num) 返回指定分组匹配到的字符串,group(0)表示匹配到的整个字符串,group(1) 表示匹配到的第一个字符(即是第一个括号中匹配的模式)

  • int groupCount() 返回匹配到的分组个数

  • String replaceAll(String str) 将所有于模式相匹配的 字符串全部替换程指定的字符串str,返回的是替换后的文本

  • String replaceFirst(String str) 只将第一次匹配到的字符串替换成指定的字符串str,返回的时替换后的文本

        Pattern pattern=Pattern.compile("\\d+");
        String str="chenjiabing2344cal3445";
        Matcher matcher=pattern.matcher(str);
        str=matcher.replaceFirst("陈加兵");   
        System.out.println(str);   //输出:chenjiabing陈加兵cal3445
        
        /*
         * str=matcher.replaceAll("陈加兵");
         * System.out.println(str)    //输出:chenjiabing陈加兵cal陈加兵
         */

捕获组

捕获组可以通过从左到右计算其开括号来编号,编号是从1 开始的。例如,在表达式 ((A)(B(C)))中,存在四个这样的组:

        ((A)(B(C)))
        (A)
        (B(C))
        (C)

总之在正则表达式中在括号中的就是一个分组,下面用一个实例来理解一下

        Pattern pattern=Pattern.compile("(\\D*)(\\d+)\\s(\\D+)");
        Matcher matcher=pattern.matcher("chenjiabingshizuibangde6666 chenjiabign");
        if(matcher.find())
        {
            System.out.println("总共匹配到了"+matcher.groupCount()+"个分组");
            System.out.println("匹配到整个字符串为"+matcher.group(0));
            System.out.println("匹配到的第一个字符串为"+matcher.group(1));
            System.out.println("匹配到的第二个字符串为"+matcher.group(2));
            System.out.println("匹配到的第三个字符串为"+matcher.group(3));
        }

贪婪模式和非贪婪模式

贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配
一般写python爬虫的时候使用的都是非贪婪模式来匹配
使用了贪婪模式后会尽可能匹配更多的字符串,即是到了正则表达式定的末尾但是还是会继续向后匹配,看看是否还能匹配,非贪婪模式则是相反,到了正则表达式定义的结束字符就直接停止匹配了
贪婪模式: .* , .+
非贪婪模式: .*? , .+?

实例

        //使用了贪婪模式,因此当匹配到第一个</div>的时候还要向后面匹配看看是否还能匹配到,由于后面还有</div>结尾的,因此还是能够匹配的,因此匹配到的是:陈加兵</div><div>郑元梅
        Pattern pattern=Pattern.compile("<div>(.*)</div>");   
        
        //使用了非贪婪模式,因此当匹配到第一个</div>的时候就不向后面匹配了,直接返回了,因此匹配到的是:陈加兵
        Pattern pattern1=Pattern.compile("<div>(.*?)</div>");   
        String str="<div>陈加兵</div><div>郑元梅</div>";
        Matcher matcher=pattern1.matcher(str);
        if(matcher.find())
        {
            System.out.println(matcher.groupCount());  //1
            System.out.println(matcher.group(1));  //输出匹配到的字符串,此时输出的是:陈加兵,如果使用贪婪模式输出的是:陈加兵</div><div>郑元梅
        }

参考文章


  1. 0-9
  2. s
  3. w
  4. abc

码猿技术专栏
486 声望108 粉丝