Java 正则表达式

正则表达式的语法

元字符-转义号\\

提示:在Java中两个 \\ 相当于其他语言中的一个\

需要用到转义符的字符有以下几个:

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

如果匹配条件只有一个 ‘.’ 的话,意思是匹配所有字符

元字符-字符匹配符

符号 含义 示例 解释
[] 可接受的字符列表 [efgh] e,f,g,h中的任意一个字符
[^] 不接收的字符列表 [^abc] 除a,b,c之外的任意一个字符,包括数字和特殊符号
连字符 A-Z 任意单个大写字母
. 匹配除 \n 以外的任意一个字符 a..b 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串
\\d 匹配单个数字字符,相当于[0-9] \\d{3}(\\d)? 包含3个或4个数字的字符串
\\D 匹配单个非数字字符,相当于[^0-9] \\D(\\d)* 以单个非数字字符夹头,后接任意个数数字字符串
\\w 匹配单个数字,大小写字母字符,相当于[0-9a-zA-Z] \\d{3}\\w{4} 以3个数字是字符开头的长度为7的数字字母字符串
\\W 匹配单个非数字,大小写字母字符,相当于[^0-9a-zA-Z] \\W+\\d{2} 以至少1个非数字字母字符开头,2个数字字符结尾的字符串
\\s 匹配任何空白字符(空格,制表符等)
\\S 匹配任意非空白字符,和\\s整好相反

一些应用实例

[a-z], [A-Z], [1-9]的说明

表示可以匹配a-z的任意一个字符, A-Z的任意一个字符,1-9的任意一个字符

[^a-z], [^A-Z], [^1-9]的说明

表示匹配的不是a-z的任意一个字符, 匹配的不是A-Z的任意一个字符,匹配的不是1-9的任意一个字符

[abcd] [^abcd]

表示匹配的是abcd中的任意一个字符,匹配的不是abcd中的任意一个字符

.

匹配 \n 之外的所有字符,如果要匹配 . 本身, 则需使用 \.

java正则表达式默认是区分字母大小写的,如何实现不区分大小写呢?以”abc”举例

  • (?i)abc 表示 abc 不区分大小写
  • a(?i)bc 表示 bc 不区分大小写
  • a((?i)b)c 表示只有 b 不区分大小写
  • Pattern pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);

元字符-选择匹配符 |

例子:

public static void main(String[] args) {
        String content = "abc 555 666";
        String reg = "abc|555|666";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }
结果返回 abc 555 666

元字符-限定符

用于指定】其前面的字符和组合项连续出现多少次

符号 含义 示例 说明 匹配输入
* 指定字符重复0次或n次(无要求) (abc)* 仅包含任意个abc的字符串 abc, abcabcabc
+ 指定字符重复1次或n次(至少一次) m+(abc)* 以至少一个m开头,后接任意个abc的字符串 m,mabc,mabcabc
? 指定字符重复0次或1次(最多1次) m+abc? 以至少一个m开头,后接ab或abc的字符串 mab,mabc,mmmab,mmabc
{n} 只能输入n个字符 [abcd]{3} 由abcd中字母组成的任意长度为3的字符串 abc,adc, bcd
{n,} 指定至少n个匹配 [abcd]{3,} 由abcd组成的至少为3的字符串 abc,adc,abcdddd
{n,m} 指定至少n个但不超过m个匹配 [abcd]{3,5} 由abcd中的字母组成的任意长度不小于3,不大于5的字符串 abc,abdc,addcb

细节:关于上述的{n,m},java进行匹配的时候默认是贪婪匹配,即尽量匹配多的,如果想要使其非贪婪匹配的话,需要在限定符后面加 ?

元字符-定位符

规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置

符号 含义 示例 说明 匹配输入
^ 指定起始字符 ^ [0-9]+[a-z]* 以至少1个数字开头,后接任意个小写字母的字符串 123, 6aa, 55edf
$ 指定结束字符 ^ [0-9]\-[a-z]+$ 以1个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串 1-a
\\b 匹配目标字符换的边界 han\\b 这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置 hanshunpingsphan nnhan
\\B 匹配目标字符串的非边界 han\\B 和\\b正好相反 hanshunpingsphan nnhan

解释一下 \\b:指的是一某个字符串结尾(空格也算作结尾),例如:”hanshunpingsphan nnhan”,则输出 两个 “han”

分组

常用分组构造形式 说明
(pattern) 非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(?pattern) 命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?’name’)

举例说明

未命名捕获

public static void main(String[] args) {
        String content = "dhviaoohdidjkad1335njdoaifjwoi1516ndkfnaeo51561";
        String reg = "(\\d\\d)(\\d\\d)"; //匹配四个数字的字符串
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
            //第一个分组
            System.out.println("第一个分组的内容" + matcher.group(1));
            //第二个分组
            System.out.println("第二个分组的内容" + matcher.group(2));
            //切记不可越界输出
            //System.out.println("第三个分组的内容" + matcher.group(3));
        }
    }

命名分组:可以给分组取名

public static void main(String[] args) {
        String content = "dhviaoohdidjkad1335njdoaifjwoi1516ndkfnaeo51561";
        String reg = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
            System.out.println("第一个分组的内容" + matcher.group(1));
            System.out.println("第一个分组的内容[通过组名]" + matcher.group("g1"));
            System.out.println("第二个分组的内容" + matcher.group(2));
            System.out.println("第二个分组的内容[通过组名]" + matcher.group("g2"));
        }
    }

给分组取了个名字,可以通过编号来取,也可以通过去的组名来取

特别分组

常用分组构造形式 说明
(?:pattern) 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符(
(?=pattern) 它是一个非捕获匹配。例如,”Windows (=95
(?!pattern]) 该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如,”Windows (?!95

(?:pattern)

public static void main(String[] args) {
        String content = "12132韩顺平教育 fewafew韩顺平老师 gdgd韩顺平同学";
        //String reg = "韩顺平教育|韩顺平老师|韩顺平同学";
        //上面的写法等价于非捕获分组,注意:不能 matcher.group(1)
        String reg = "韩顺平(?:教育|老师|同学)";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }

(?=pattern)

public static void main(String[] args) {
        String content = "12132韩顺平教育 fewafew韩顺平老师 gdgd韩顺平同学";
        //下面是非捕获分组,也不能使用 matcher.group(1)
        String reg = "韩顺平(?=教育|老师)";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }

(?!pattern)

public static void main(String[] args) {
        String content = "12132韩顺平教育 fewafew韩顺平老师 gdgd韩顺平同学";
        //下面是非捕获分组,也不能使用 matcher.group(1)
        String reg = "韩顺平(?!教育|老师)";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }

正则表达式三个常用类

Pattern 类

pattern对象是一个正则表达式对象。Pattern 类没有公共构造方法。要创建一个 Pattern对象,调用其公共静态方法,它返回一个 Pattern对象。该方法接受一个正则表达式作为它的第·一个参数,比如: Patternr = Pattern.compile(pattern);

部分方法

整体匹配: Pattern.matches()(想起验证某个字符串是否符合条件,返回的是真或者假)

public static void main(String[] args) {
        String content = "hello abc 111";
        String reg = "hello.*";
        boolean matches = Pattern.matches(reg, content);
        System.out.println("匹配结果: " +  matches);
    }

Matcher 类

Matcher 对象是对输入字符串进行解释和匹配的引擎。与Patterr类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象

方法一览

public int start()返回以前匹配的初始索引。
public int start(int group)返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引public int end()返回最后匹配字符之后的偏移量。
public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配。
public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配。
public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配。
public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配。
public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤。
public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换步骤。
public String replaceAll(String replacement)替换模式与给定替换字符串相匹配的输入序列的每个子序列。(返回的字符串才是改变之后的字符串)
public String replaceFirst(String replacement)替换模式与给定替换字符串匹配的输入序列的第一个子序列。
public static String quoteReplacement(String s)返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作。
public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤。
public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换步骤。

PatternSyntaxException 类

PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

分组,捕获,反向引用之间的关系

介绍

1.分组
我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/一个分组。
2捕获
把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式
3.反向引用
圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\\分组号,外部反向引用$分组号

提出问题:给你一段文本,请你找出所有四个数字连在一起的子串,并且这四个数字要满足④第1位与·第4位相同②第2位与第3位相同,比如1221,5775 ..
反向引用案例:

public static void main(String[] args) {
        
        String content = "hello abc 1111 afda2332";
        //下面是非捕获分组,也不能使用 matcher.group(1)
        String reg = "(\\d)(\\d)\\2\\1";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()) {
            System.out.println("匹配结果: " +  matcher.group(0));
        }
}

案例:
问题:把类似”我…我要…学学学学…编程java!” 利用正则表达式改成 “我要学编程java!”

public static void main(String[] args) {
        
        String content = "我...我要...学学学学...编程java!";
        // 1. 去掉所有的 .
        Pattern pattern = Pattern.compile("\\.");
        Matcher matcher = pattern.matcher(content);
        content = matcher.replaceAll("");
        System.out.println("content : " + content);
        // 2. 去掉重复的字 我我要学学学学编程java!

        // 思路;
        // (1) 使用 (.)\\1+ 匹配相邻个数大于等于2的子串
        // (2) 使用反向引用$1 来替换匹配到的内容
        //注意:这里正则表达式变化,所以要重置 matcher
        //pattern = Pattern.compile("(.)\\1+");  //分组的捕获内容记录到$1
        //matcher = pattern.matcher(content);
        //while (matcher.find()) {
        //    System.out.println("找到 = " + matcher.group(0));
        //}
        //使用反向引用 $1 来替换匹配到的内容
        //content = matcher.replaceAll("$1");
        //System.out.println("content = " + content);

        // (3) 使用一条语句去掉重复的字
        content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
        System.out.println("content = " + content);
    }

String 类中也可以直接使用正则表达式

替换功能

String 类 public String replaceAll(String regex,String replacement)

判断功能

String 类 public boolean matches(String regex){} //使用 Pattern 和 Matcher 类

分割功能

String 类 public String[] split(String regex)

Tags: