Java 正则表达式语法介绍

2021-10-30 0 By admin

如果想要灵活的运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为

  1. 转义符
  2. 字符匹配符
  3. 选择匹配符
  4. 限定符
  5. 定位符
  6. 捕获分组和非捕获分组

一、转义符

在我们使用正则表达式去检索某些特殊字符的时候,需要用到转移符号。
如要匹配“abc$(”的话,就需要将其中的”$”前加”\\” 转移符。
在 Java 的正则表达式中,两个斜线代表转移符,其他语言多用一个斜线。

String content = "abc$(a.bc(123(";
Pattern compile = Pattern.compile("\\(");
// 2.创建一个匹配器对象
Matcher matcher = compile.matcher(content);
// 3. 可以循环匹配
while (matcher.find()) {
  // 匹配内容,文本,放到 m.group(0)
  System.out.println("找到:" + matcher.group(0));
}

需要用到转义的特殊字符包括:.*()$/\?[]^{}

二、字符匹配符

符号 含义 示例 说明
[] 可接收的字符列表 [efgh] e、f、g、h中的任意一个字符
[^] 不接收的字符列表 [^abc] 除了a、b、c 以外的任意一个字符,包括数字和特殊符号
连字符 A-Z 任意单个大写字母
字符匹配符补充
字符匹配符补充
字符匹配符中的大小写匹配
字符匹配符中的大小写匹配
    String content = "a11c8abcAB\nCy_ABC abc@!  .";

    String reg = "[a-z]"; // 匹配 a-z之间任意一个字符
    String reg1 = "[A-Z]"; // 匹配 A-Z之间任意一个字符
    String reg2 = "abc"; // 匹配 abc字符串(默认区分大小写)
    String reg3 = "(?i)abc"; //匹配 abc 字符串[不区分大小写]
    String reg4 = "[0-9]"; // 匹配 0-9之间任意一个字符
    String reg5 = "[^a-z]"; // 匹配 不在 a-z之间任意一个字符
    String reg6 = "[^0-9]"; // 匹配 不在 0-9之间任意一个字符
    String reg7 = "[abcd]"; // 匹配 在 abcd中任意一个字符
    String reg8 = "\\D"; // 匹配 不在 0-9的任意一个字符
    String reg9 = "\\w"; // 匹配 大小写英文字母,数字,下划线
    String reg10 = "\\W"; // 等价于 [^a-zA-Z0-9_],比如空格,感叹号!,艾特@
    String reg11 = "\\s"; // 匹配任何空白字符(空格,制表符等)
    String reg12 = "\\S"; // 表示,非空白就匹配,与\\s相反
    String reg13 = "\\."; // "."匹配出 \n之外的所有字符,如果要匹配,本身则需要使用 \\.

    Pattern compile = Pattern.compile(reg12);
    // 启用不区分大小写的匹配。
    // Pattern compile = Pattern.compile(reg2, Pattern.CASE_INSENSITIVE);
    Matcher matcher = compile.matcher(content);
    while (matcher.find()) {
      System.out.println("找到:" + matcher.group(0));
    }

三、选择匹配符

在匹配某个字符串的时候是选择性的,既可以匹配这个,也可以匹配那个。

符号 含义 示例 说明
| 匹配“|”之前或之后的表达式 ab|cd ab或者cd
String content = "lauy 木艺术";
String regStr = "lauy|木|艺";
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
  System.out.println("找到:" + matcher.group(0));
}

四、限定符

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

限定符
限定符
String content = "111112141aaaaa1ahello";

String reg1 = "a{3}"; // 表示匹配 aaa
String reg2 = "1{4}"; // 表示匹配 1111
String reg3 = "\\d{2}"; // 表示匹配 两位的任意数字字符
// 细节:java匹配默认贪婪匹配,尽可能的匹配多的
String reg4 = "a{3,4}"; //表示匹配aaa 或者 aaaa,优先aaaa多的
String reg5 = "1{4,5}"; // 表示匹配 1111 或者 11111
String reg6 = "\\d{2,5}"; // 匹配2位数或者3,4,5,如下会找到找到:11111 和 11
// + 号使用
String reg7 = "1+"; // 匹配一个1或者多个1
String reg8 = "\\d+"; // 匹配一个或多个数字
String reg11 = "\\d*"; // 匹配0个或多个数字
// * 号使用
String reg9 = "1*"; // 匹配0个1或者多个1
// ? 号使用,遵守贪婪匹配
String reg10 = "a1?"; // 匹配 a 或者 a1
Pattern pattern = Pattern.compile(reg11, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
  System.out.println("找到:" + matcher.group(0));
}

五、定位符

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

定位符
定位符
  String content = "21lauyhelloworld hilauy lauyu Hilauy123";

  // 以至少1个数字开头,后接0或者任意个小写字符串
  String reg1 = "^[0-9]+[a-z]*";
  // 以至少1个数字开头,必须以至少一个小写字母结束,比如仅仅跟 2-lauyhelloworld 匹配,就符合要求
  String reg2 = "^[0-9]+\\-[a-z]+$";

  // 匹配一个单词边界,即字与空格间的位置。如果它位于要匹配的字符串的开始,它在单词的开始处查找匹配项。如果它位于字符串的结尾,它在单词的结尾处查找匹配项。
  // 上述例子,我们可以找字符串结尾处的,比如 21lauyh...,lauyu,lauy123
  String reg3 = "lauy\\b";

  // 和\\b含义相反,详细:面表达式匹配 minelauyo 中的字符串 apt,但不匹配 lauyo 中的字符串 apt:
  String reg4 = "lauy\\B";

  Pattern pattern = Pattern.compile(reg4);
  Matcher matcher = pattern.matcher(content);

  while (matcher.find()) {
    System.out.println("找到:" + matcher.group(0));
  }

六、分组

正则表达式中分组可以分为捕获分组和非捕获分组。

1、分组
用圆括号组成一个比较复杂的匹配模式,一个圆括号的部分可以看作一个子表达式/一个分组。
2、捕获
把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显示命名的组里,方便后面引用。
从左到右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式。

6.1、捕获分组

捕获分组
捕获分组
String content = "1324324332423";
/* 捕获分组*/
String reg1 = "(\\d\\d)(\\d\\d)"; // 匹配4个数字的字符串
// 命名分组:即可以给分组取名
String reg2 = "(?<g1>\\d\\d)(?<g2>\\d\\d)";

Pattern pattern = Pattern.compile(reg2);
Matcher matcher = pattern.matcher(content);

while (matcher.find()) {
 /*找到:1324
 找到第一个分组的第一个内容:13
 找到第一个分组的第一个内容:24*/
 System.out.println("找到捕获分组:" + matcher.group(0));
 System.out.println("找到捕获分组的第一个内容:" + matcher.group(1));
 System.out.println("找到捕获分组的第二个内容:" + matcher.group(2));

 /*命名分组方式*/
 // System.out.println("找到捕获分组:" + matcher.group(0));
 // System.out.println("找到第捕获分组的第一个内容:" + matcher.group("g1"));
 // System.out.println("找到第捕获分组的第二个内容:" + matcher.group("g2"));
}

6.2、非捕获分组

非捕获分组
非捕获分组
/* 非捕获分组,注意不能 matcher.group(1) */
String content1 = "梦想天空分外蓝啊、分外蓝呀、分外蓝";

// 等同于 "分外蓝|分外蓝啊|分外蓝呀"
// 输出:找到非捕获分组:分外蓝啊 找到非捕获分组:分外蓝呀
String reg3 = "分外蓝(?:啊|呀)";

// 找到分外蓝关键字,但是要求只是查询 分外蓝啊 和 分外蓝呀 中的分外蓝
// 输出:找到非捕获分组:分外蓝
String reg4= "分外蓝(?=啊|呀)";

// 找到分外蓝关键字,但是要求只是查询匹配 不是 分外蓝啊 和 分外蓝呀 中包含有的分外蓝
// 输出:找到非捕获分组:分外蓝啊 找到非捕获分组:分外蓝呀
String reg5= "分外蓝(?:啊|呀)";

Pattern pattern = Pattern.compile(reg5);
Matcher matcher = pattern.matcher(content1);

while (matcher.find()) {
  System.out.println("找到非捕获分组:" + matcher.group(0));
}

6.3、反向引用-内部引用

圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较使用的匹配模式,称为反向引用。
反向引用可以在正则表达式内部,也可以在正则表达式的外部;内部的反向引用\\分组号,外部的反向引用$分组号

// String content = "h1234e155111111abad12321-33344455512211";
String content = "1221 1111 1111 123213";

// 匹配两个连续的相同数字:(\\d)\\1
String reg1 = "(\\d)\\1";
// 匹配五个连续的相同的数字 11111
String reg2 = "(\\d)\\1{4}";
// 匹配个位与千位相同,十位与百位相同的数,匹配1111
String reg3 = "(\\d)(\\d)\\2\\1";
// 匹配前面是一个五位数,然后一个 -号,然后是一个九位数,连续的每三位要相同,匹配12321-333444555
String reg4 = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
// 匹配123213,(\\d)(\\d)(\\d)\\2\\1中 \\2表示反向引用123三个数字中的第二位2,同理\\1,\\3也是如此
String reg5 = "(\\d)(\\d)(\\d)\\2\\1\\3";
Pattern compile = Pattern.compile(reg5);
Matcher matcher = compile.matcher(content);
while (matcher.find()) {
  System.out.println("匹配格式:" + matcher.group(0));
}

6.4、反向引用-外部引用

String content = "我我我要学学学编程java!!!";
String reg = "(.)\\1+";
Pattern compile = Pattern.compile(reg);
Matcher matcher = compile.matcher(content);
while (matcher.find()) {
  System.out.println("匹配格式:" + matcher.group(0));
}
// 使用 反向引用$1 来替换匹配的内容
String result = Pattern.compile(reg).matcher(content).replaceAll("$1");
System.out.println("去重后:" + result);