Java学习笔记——正则表达式(Pattern类、Matcher类和PatternSyntaxException)

目录

一、Pattern类

(一)Pattern 介绍

(二)Pattern 方法

二、Matcher类

(一)Matcher 类介绍

(二)Matcher 类方法

三、PatternSyntaxException 

四、代码 


Java中与正则表达式相关的类分别为:Pattern 类、Matcher 类和PatternSyntaxException。

三类的功能:pattern 对象是一个正则表达式的编译表示;Matcher 对象是对输入字符串进行解释和匹配操作的引擎;PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

本文将对这三类常用的基本方法进行简单的介绍。

一、Pattern类

(一)Pattern 介绍

  • Pattern类在java.util.regex 包中 ,且是正则表达式的编译表示形式;
  • Pattern类由final修饰,因此不能被子类继承;
  • Pattern类的实例不可变,可供多个并发线程安全使用;
  • Pattern的构造器是私有的,不能通过new创建Pattern对象,可以通过Pattern调用静态方法compile返回Pattern实例。

(二)Pattern 方法

1、compile():获取Pattern实例

由于Pattern构造器是私有的,所以不可以通过new创建Pattern对象,可以通过Pattern调用静态方法compile返回Pattern实例。

获取Pattern类的实例有两种方法:

Pattern compile(String regex):

regex正则表达式,该方法是将给定的正则表达式编译并赋予给Pattern类

public static Pattern compile(String regex) {
        return new Pattern(regex, 0);
    }

Pattern compile(String regex, int flags):

regex正则表达式,flags控制匹行为的参数,该方法是将给定的正则表达式编译并赋予给Pattern类

public static Pattern compile(String regex, int flags) {
        return new Pattern(regex, flags);
    }

关于参数flag,有以下特定值

  1. UNIX_LINES:unix lines模式,该模式下,仅以\n为结尾(行一般以\n或\r\n结尾);
  2. CASE_INSENSITIVE:忽略大小写进行匹配;
  3. COMMENTS:忽略空格字符(例如,表达式里的空格,tab,回车)和注释(从#开始,一直到行结束);
  4. MULTILINE:多行模式的开启,在多行模式下,^匹配输入字符串开始的位置,$匹配输入字符串结尾的位置;
  5. DOTALL:dotall模式,"."匹配所有字符,包括行终结符。(若该模式未开启,“.”表达式不匹配行终结符);
  6. UNICODE_CASE:UNICODE_CASE模式结合CASE_INSENSITIVE模式,那么它会对Unicode字符进行大小写不敏感的匹配。(若未开启UNICODE_CASE模式,仅开始CASE_INSENSITIVE模式,则只适用于US-ASCII字符集);
  7. CANON_EQ:当且仅当两个字符的正规分解都完全相同的情况下,则认定匹配。(默认情况下,不考虑规范相等性);

2、split():拆分字符串

Pattern.split() 将字符串从正则表达式匹配的地方分开

split(CharSequence input)

input 要拆分的字符序列

返回:根据围绕此模式的匹配来拆分输入后所计算的字符串数组

代码实例

String str = "name:'Jack',age:18,sex=M,height:180cm,weight:60kg";

// compile()
Pattern p = Pattern.compile("\\d");

// split()
String[] arr1 = p.split(str); 

Debug

String[] split(CharSequence input, int limit)

input 要拆分的字符序列

limit 结果阈值,控制应用模式的次数,从而影响结果数组的长度

  1. 若 limit > 0:split最多应用limit - 1次,数组的长度不大于limit,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入;
  2. 若 limit < 0:split次数不受限制,数组为任意长度;
  3. 若 limit = 0:split次数不受限制,数组为任意长度,但会摒弃尾部的空字符串;

返回:根据围绕此模式的匹配来拆分输入后所计算的字符串数组

代码实例

String str = "name:'Jack',age:18,sex=M,height:180cm,weight:60kg0000";

// compile()
Pattern p = Pattern.compile("\\d");

// split()
String[] arr2 = p.split(str, -1);
String[] arr3 = p.split(str, 2);
String[] arr4 = p.split(str, 5);
String[] arr5 = p.split(str, 0);

Debug

  • arr2中,limit = -1 < 0,数组长度无限制,即数组长度为12,其中包含几个空字符串
  • arr3中,limit = 2 > 0,split()最多使用1次,即数组长度最长为2
  • arr4中,limit = 5 > 0,split()最多使用4次,即数组长度最长为5
  • arr5中,limit = 0 == 0,split无限制,即数组长度无限制,但会摒弃尾部空字符串

arr2

 arr3

 arr4

arr5

3、matcher():匹配字符串或者返回Matcher实例

Pattern.matcher():或返回一个Matcher实例;

Pattern.matcher():对整个字符串进行匹配,若整个字符串都匹配,返回true;

Pattern.matcher(String regex,CharSequence input)

regex 正则表达式

input 待匹配的字符串

代码实例

// matcher()
System.out.println(Pattern.matches("\\d+", "123456"));  // true
System.out.println(Pattern.matches("\\d+", "aa123456"));  // false,需要匹配到所有字符串才能返回true,这里aa不能匹配到

输出结果

二、Matcher类

(一)Matcher 类介绍

  • Matcher类在java.util.regex 包中 ,表示执行各种匹配操作的引擎;
  • Matcher类由final修饰,因此不能被子类继承;
  • Matcher类实例用于多个并发线程不安全;
  • 该类没有构造函数,可以使用matches()java.util.regex.Pattern类的方法创建/获取该类的对象。

(二)Matcher 类方法

Matcher 对象是对输入字符串进行解释和匹配操作的引擎,与Pattern 类一样,Matcher 也没有公共构造方法;

1、查找方法

  • find():对字符串进行匹配,匹配到的字符串可以在任何位置,若匹配到,返回true,否则,false(即,只要匹配到
  • lookingAt():对前面的字符串进行匹配,只有匹配到的字符串在最前面,返回true,否则,false(即,匹配且必须在首位
  • matches(): 对整个字符串进行匹配,若整个字符串都匹配,返回true,否则,false(即,整个字符串全部匹配

代码实例

// find(): 对字符串进行匹配,匹配到的字符串可以在任何位置, 若匹配到, 返回true, 否则, false
String str1 = "I love Java, Python, Java Java and Java!";

Pattern p1 = Pattern.compile("\\bJava\\b");
Pattern p2 = Pattern.compile("\\d");
Matcher m1 = p1.matcher(str1);
Matcher m2 = p2.matcher(str1);

System.out.println(m1.find());  // true, 字符串中有"Java", 因此返回true
System.out.println(m2.find());  // false, 字符串中没有数字, 因此返回false

// lookingAt(): 对前面的字符串进行匹配,只有匹配到的字符串在最前面,返回true,否则,false
String str3 = "123456";
String str4 = "abc123456";

Pattern p3 = Pattern.compile("\\d+");
Matcher m3 = p3.matcher(str3);
Matcher m4 = p3.matcher(str4);

System.out.println(m3.lookingAt());  // true, 字符串开头是数字
System.out.println(m4.lookingAt());  // false, 字符串开头不是数字

// matches(): 对整个字符串进行匹配,若整个字符串都匹配,返回true,否则,false
System.out.println(m3.matches());  // true, 全部是数字
System.out.println(m4.matches());  // false, 字符串开头不是数字

2、索引方法

  • start(): 返回匹配到的子字符串的第一个字符在原字符串中的索引位置
  • end(): 返回匹配到的子字符串的最后一个字符在原字符串中的索引位置
  • group(): 返回匹配到的子字符串

代码实例1

// start(): 返回匹配到的子字符串的第一个字符在原字符串中的索引位置
// end(): 返回匹配到的子字符串的最后一个字符在原字符串中的索引位置
// group(): 返回匹配到的子字符串
String str5 = "aa12cc3456bb";
Pattern p5 = Pattern.compile("\\d+");
Matcher m5 = p5.matcher(str5);
while (m5.find()){
    System.out.println("匹配到的子字符串group(): " + m5.group());  // 12, 3456
    System.out.println("匹配到的子字符串第一个字符索引start(): " + m5.start());  // 2, 6 第一个子字符串的第一个字符索引:2, 第二个子字符串的第一个字符索引:6
    System.out.println("匹配到的子字符串最后一个字符索引end(): " + m5.end()); // 4, 10 第一个子字符串的最后一个字符索引:4, 第二个子字符串的最后一个字符索引:10
}

输出结果1

  • start(int i): 匹配到的子字符串第i组第一个字符索引
  • end(int i): 匹配到的子字符串第i组最后一个字符索引
  • group(int i): 匹配到的子字符串的第i组
  • groupCount(): 返回分组的数量

代码实例2

// start(int i): 匹配到的子字符串第i组第一个字符索引
// end(int i): 匹配到的子字符串第i组最后一个字符索引
// group(int i): 匹配到的子字符串的第i组
// groupCount(): 返回分组的数量
String str6 = "aa12cc3456bb";
Pattern p6 = Pattern.compile("([a-z]+)(\\d+)");  // 字母 + 数字
Matcher m6 = p6.matcher(str6);

System.out.println("正则表达式的分组共" + m6.groupCount() + "组");
while (m6.find()){
    System.out.println("匹配到的子字符串group(): " + m6.group());  // aa12, cc3456

    System.out.println("匹配到的子字符串的第一组group(1): " + m6.group(1));  // aa, cc
    System.out.println("匹配到的子字符串的第二组group(2): " + m6.group(2));  // 12, 3456

    System.out.println("匹配到的子字符串第一组第一个字符索引start(1): " + m6.start(1));  // aa12中第一组为aa, 索引:0  cc3456中第一组为cc, 索引:4
    System.out.println("匹配到的子字符串第二组第一个字符索引start(2): " + m6.start(2));  // aa12中第一组为12, 索引:2  cc3456中第二组为3456, 索引:6

    System.out.println("匹配到的子字符串第一组最后一个字符索引end(1): " + m6.end(1));  // aa12中第一组为aa, 索引:2  cc3456中第一组为cc, 索引:6
    System.out.println("匹配到的子字符串第二组最后一个字符索引end(2): " + m6.end(2));  // aa12中第一组为12, 索引:4  cc3456中第二组为3456, 索引:10
}

输出结果2 

3、替换方法

  • replace(CharSequence target, CharSequence replacement):用replacement替换所有的target,两个参数都是字符串;
  • replaceAll(String regex, String replacement):用replacement替换所有的regex匹配项,regex是正则表达式,replacement是字符串;
  • replaceFirst(String regex, String replacement):基本和replaceAll相同,区别是只替换第一个匹配项;

代码实例1

String str7 = "I love Java、java(Java) and Python!";
Pattern p7 = Pattern.compile("\\bJava\\b");
Matcher m7 = p7.matcher(str7);
// replaceAll(String regex, String replacement):用replacement替换所有的regex匹配项,regex是正则表达式,replacement是字符串
System.out.println("replaceAll(): " + m7.replaceAll("C++"));  // I love C++、java(C++) and Python!

// replaceFirst(String regex, String replacement):基本和replaceAll相同,区别是只替换第一个匹配项
System.out.println("replaceFirst(): " + m7.replaceFirst("C++"));  // I love C++、java(Java) and Python!

// replace(CharSequence target, CharSequence replacement):用replacement替换所有的target,两个参数都是字符串
System.out.println("replace(): " + "I love Java、java(Java) and Python!".replaceAll("Java", "C++"));  // I love C++、java(C++) and Python!

输出结果1

  • appendReplacement():实现非终端添加和替换步骤,将当前匹配子串替换为指定字符串,并将从上次匹配结束后到本次匹配结束后之间的字符串添加到一个StringBuffer对象中,最后返回其字符串表示形式。(注:对于最后一次匹配,其后的字符串并没有添加入StringBuffer对象中,若需要这部分的内容需要使用appendTail方法);
  • appendTail():实现终端添加和替换步骤,将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里;

代码实例2

// appendReplacement(): 实现非终端添加和替换步骤
// appendTail():实现终端添加和替换步骤
String str8 = "aabfooaabfooabfoobkkk";
Pattern p8 = Pattern.compile("a*b");
Matcher m8 = p8.matcher(str8);

StringBuffer sb = new StringBuffer();
while (m8.find()){
    m8.appendReplacement(sb, "*");
}
System.out.println("appendReplacement(): " + sb.toString()); // *foo*foo*foo*
m8.appendTail(sb);
System.out.println("appendTail(): "+ sb.toString());  // *foo*foo*foo*kkk

输出结果2 

三、PatternSyntaxException 

  • getDescription():获取错误的描述
  • getIndex():获取错误的索引
  • getPattern():获取错误的正则表达式模式
  • getMessage():返回多行字符串,包含语法错误及其索引的描述、
  • 错误的正则表达式模式和模式中错误索引的可视化指示

四、代码 

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

public class Day12 {
    public static void main(String[] args) {
        /* Pattern */
        String str = "name:'Jack',age:18,sex=M,height:180cm,weight:60kg0000";

        // compile()
        Pattern p = Pattern.compile("\\d");

        // split()
        String[] arr1 = p.split(str);
        String[] arr2 = p.split(str, -1);
        String[] arr3 = p.split(str, 2);
        String[] arr4 = p.split(str, 5);
        String[] arr5 = p.split(str, 0);

        // matcher()
        System.out.println(Pattern.matches("\\d+", "123456"));  // true
        System.out.println(Pattern.matches("\\d+", "aa123456"));  // false,需要匹配到所有字符串才能返回true,这里aa不能匹配到

        /* Matcher */
        // find(): 对字符串进行匹配,匹配到的字符串可以在任何位置, 若匹配到, 返回true, 否则, false
        String str1 = "I love Java, Python, Java Java and Java!";

        Pattern p1 = Pattern.compile("\\bJava\\b");
        Pattern p2 = Pattern.compile("\\d");
        Matcher m1 = p1.matcher(str1);
        Matcher m2 = p2.matcher(str1);

        System.out.println(m1.find());  // true, 字符串中有"Java", 因此返回true
        System.out.println(m2.find());  // false, 字符串中没有数字, 因此返回false

        // lookingAt(): 对前面的字符串进行匹配,只有匹配到的字符串在最前面,返回true,否则,false
        String str3 = "123456";
        String str4 = "abc123456";

        Pattern p3 = Pattern.compile("\\d+");
        Matcher m3 = p3.matcher(str3);
        Matcher m4 = p3.matcher(str4);

        System.out.println(m3.lookingAt());  // true, 字符串开头是数字
        System.out.println(m4.lookingAt());  // false, 字符串开头不是数字

        // matches(): 对整个字符串进行匹配,若整个字符串都匹配,返回true,否则,false
        System.out.println(m3.matches());  // true, 全部是数字
        System.out.println(m4.matches());  // false, 字符串开头不是数字

        // start(): 返回匹配到的子字符串的第一个字符在原字符串中的索引位置
        // end(): 返回匹配到的子字符串的最后一个字符在原字符串中的索引位置
        // group(): 返回匹配到的子字符串
        String str5 = "aa12cc3456bb";
        Pattern p5 = Pattern.compile("\\d+");
        Matcher m5 = p5.matcher(str5);
        while (m5.find()){
            System.out.println("匹配到的子字符串group(): " + m5.group());  // 12, 3456
            System.out.println("匹配到的子字符串第一个字符索引start(): " + m5.start());  // 2, 6 第一个子字符串的第一个字符索引:2, 第二个子字符串的第一个字符索引:6
            System.out.println("匹配到的子字符串最后一个字符索引end(): " + m5.end()); // 4, 10 第一个子字符串的最后一个字符索引:4, 第二个子字符串的最后一个字符索引:10
        }

        // start(int i): 匹配到的子字符串第i组第一个字符索引
        // end(int i): 匹配到的子字符串第i组最后一个字符索引
        // group(int i): 匹配到的子字符串的第i组
        // groupCount(): 返回分组的数量
        String str6 = "aa12cc3456bb";
        Pattern p6 = Pattern.compile("([a-z]+)(\\d+)");  // 字母 + 数字
        Matcher m6 = p6.matcher(str6);

        System.out.println("正则表达式的分组共" + m6.groupCount() + "组");
        while (m6.find()){
            System.out.println("匹配到的子字符串group(): " + m6.group());  // aa12, cc3456

            System.out.println("匹配到的子字符串的第一组group(1): " + m6.group(1));  // aa, cc
            System.out.println("匹配到的子字符串的第二组group(2): " + m6.group(2));  // 12, 3456

            System.out.println("匹配到的子字符串第一组第一个字符索引start(1): " + m6.start(1));  // aa12中第一组为aa, 索引:0  cc3456中第一组为cc, 索引:4
            System.out.println("匹配到的子字符串第二组第一个字符索引start(2): " + m6.start(2));  // aa12中第一组为12, 索引:2  cc3456中第二组为3456, 索引:6

            System.out.println("匹配到的子字符串第一组最后一个字符索引end(1): " + m6.end(1));  // aa12中第一组为aa, 索引:2  cc3456中第一组为cc, 索引:6
            System.out.println("匹配到的子字符串第二组最后一个字符索引end(2): " + m6.end(2));  // aa12中第一组为12, 索引:4  cc3456中第二组为3456, 索引:10
        }

        String str7 = "I love Java、java(Java) and Python!";
        Pattern p7 = Pattern.compile("\\bJava\\b");
        Matcher m7 = p7.matcher(str7);
        // replaceAll(String regex, String replacement):用replacement替换所有的regex匹配项,regex是正则表达式,replacement是字符串
        System.out.println("replaceAll(): " + m7.replaceAll("C++"));  // I love C++、java(C++) and Python!

        // replaceFirst(String regex, String replacement):基本和replaceAll相同,区别是只替换第一个匹配项
        System.out.println("replaceFirst(): " + m7.replaceFirst("C++"));  // I love C++、java(Java) and Python!

        // replace(CharSequence target, CharSequence replacement):用replacement替换所有的target,两个参数都是字符串
        System.out.println("replace(): " + "I love Java、java(Java) and Python!".replaceAll("Java", "C++"));  // I love C++、java(C++) and Python!

        // appendReplacement(): 实现非终端添加和替换步骤
        // appendTail():实现终端添加和替换步骤
        String str8 = "aabfooaabfooabfoobkkk";
        Pattern p8 = Pattern.compile("a*b");
        Matcher m8 = p8.matcher(str8);

        StringBuffer sb = new StringBuffer();
        while (m8.find()){
            m8.appendReplacement(sb, "*");
        }
        System.out.println("appendReplacement(): " + sb.toString()); // *foo*foo*foo*
        m8.appendTail(sb);
        System.out.println("appendTail(): "+ sb.toString());  // *foo*foo*foo*kkk
    }
}
  • 14
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值