Java Regex 正则表达式

前言

1、正则表达式

  • 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个 “规则字符串”,这个 “规则字符串” 用来表达对字符串的一种过滤逻辑。

  • 在很多文本编辑器或其他工具里,正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容。

  • 许多程序设计语言都支持利用正则表达式进行字符串操作。

  • 给定一个正则表达式和另一个字符串,我们可以达到如下的目的

    • 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
    • 可以通过正则表达式,从字符串中获取我们想要的特定部分。
  • 正则表达式的特点是

    • 灵活性、逻辑性和功能性非常的强;
    • 可以迅速地用极简单的方式达到字符串的复杂控制;
    • 对于刚接触的人来说,比较晦涩难懂。
  • Java 包 java.util.regex 包含三个类,以支持正则表达式的完整版本。

    • Pattern 模式:保存正则表达式的编译形式
    • Matcher 匹配:将要匹配的字符串与模式相关联,并执行实际匹配
    • PatternSyntaxException:表示格式错误的正则表达式中的错误
  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    String str = "Java 4";

    String regex = "Java \\d"; // 使用 \d 匹配所有数字,第一个 \ 在字符串中用于转义 \d
    Pattern pattern = Pattern.compile(regex);

    Matcher matcher = pattern.matcher(str); // 进行匹配

    if (matcher != null) {
    System.out.println(matcher.find()); // 结果 true
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    String str = "asdf Java2s.com";

    String regex = "\\w+"; // 使用 \w+ 匹配任何单词
    Pattern pattern = Pattern.compile(regex);

    Matcher matcher = pattern.matcher(str); // 进行匹配

    if (matcher.find()) {
    System.out.println("GROUP 0: " + matcher.group(0)); // 结果 GROUP 0: asdf
    }

1.1 模式

  • 没有公共构造函数的模式 Pattern 是不可变的,可以共享。

    1
    2
    String regex = "Java \\d";
    Pattern pattern = Pattern.compile(regex);
  • Pattern 类包含一个静态 compile() 方法,它返回一个 Pattern 对象。

  • compile() 方法是重载的。

    1
    2
    static Pattern compile(String regex)
    static Pattern compile(String regex, int flags)
  • flags 参数是一个位掩码,并在 Pattern 类中定义为 int 常量。

Flag 描述
Pattern.CANON_EQ 启用规范等效。
Pattern.CASE_INSENSITIVE 启用不区分大小写的匹配。
Pattern.COMMENTS 启用不区分大小写的匹配。…
Pattern.DOTALL 允许在模式中的空格和注释。
忽略以#开头的空格和嵌入的注释,直到行的结尾。
Pattern.LITERAL 启用模式的文字解析。这个标志使元字符和转义序列作为正常字符。
Pattern.MULTILINE 启用多行模式。默认情况下,^$ 匹配输入序列的开始和结束。此标志使模式仅逐行匹配或输入序列的末尾。
Pattern.UNICODE_CASE 启用支持 Unicode 的大小写。与 CASE_INSENSITIVE 标志一起,可以根据 Unicode 标准执行不区分大小写的匹配。
Pattern.UNICODE_ CHARACTER_CLASS 启用预定义字符类和 POSIX 字符类的 Unicode 版本。设置此标志时,预定义字符类和 POSIX 字符类符合 Unicode 技术标准。
Pattern.UNIX_LINES 启用 Unix 行模式。设置此标志时,只有 \ n 字符被识别为行终止符。

1.2 匹配

  • Matcher 类对字符序列执行匹配通过解释在 Pattern 对象中定义的编译模式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    String str = "Java 4";
    String regex = "Java \\d";
    Pattern pattern = Pattern.compile(regex);

    Matcher matcher = pattern.matcher(str);

    if (matcher != null) {
    System.out.println(matcher.find());
    }
  • Pattern 类的 matcher() 方法创建一个实例的 Matcher 类。

  • 匹配器的以下方法执行匹配。

方法 介绍
find 找到输入中的模式的匹配,如果成功,它返回 true。否则,它返回 false。
第一次调用 find()在输入的开始处开始搜索。下一个调用将在上一次匹配后开始搜索
start 返回上一次匹配的开始索引
end 返回匹配字符串中最后一个字符的索引加 1
group 返回找到的字符串

2、元字符

  • 元字符是在 Java 正则表达式中具有特殊含义的字符。Java 中的正则表达式支持的元字符如下。

    1
    ( ) [ ] { \ ^ $ | ? * + . < > - = !
  • 字符类

    • 字符类是一组字符。正则表达式引擎将尝试匹配集合中的一个字符。
    • 元字符 [] 指定正则表达式中的字符类。
    • 范围使用连字符 - 字符表示。
    • ^ 出现在字符类中,如果在开头,表示不是。不在开头,它只匹配一个 ^ 字符。
  • 字符类的示例

字符类 含义
[abc] 字符 a,b 或 c
[^xyz] 除 x,y 和 z 以外的字符
[ABC ^] 将匹配 A,B,C 或 ^
[a-z] 表示任何小写英文字母,即 a 到 z
[a-cx-z] 字符 a 到 c 或 x 到 z,其将包括 a,b,c,x,y 或 z
[0-9] 表示 0 和 9 之间的任何数字
[0-9&&[4-8]] 两个范围 (4, 5, 6, 7 或 8) 的交叉
[a-z&&[^aeiou]] 所有小写字母减元音
  • 预定义字符类
预定义字符类 含义
. 任何字符
\d 数字。与 [0-9] 相同
\D 非数字。与 [^ 0-9] 相同
\s 空格字符。包括与 [\\ t \\ n \\ x0B \\ f \\ r] 相同。
空格
标签
换行符
垂直标签
表单 Feed
回车字符
\S 非空白字符。与 [^ \ s] 相同
\w 一个字符。与 [a-zA-Z_0-9] 相同。
\W 非字字符。与 [^ \ w] 相同。

3、量词

  • 可以指定正则表达式中的字符的次数可以匹配字符序列。

  • 为了使用正则表达式表达一个数字或更多的模式,可以使用量词。

    1
    2
    String regex = "\\w+";                                        // 使用 \w+ 匹配任何单词
    Pattern pattern = Pattern.compile(regex);
  • 量词必须遵循字符或字符类。

量词 含义
* 零次或更多次
+ 一次或多次
? 一次或根本不
{m} 正好 m 次
{m,} 至少 m 次
{m,n} 至少 m,但不超过 n 次

4、边界

  • 要匹配一行的开头,或匹配整个单词,不是任何单词的一部分,必须为匹配器设置边界。

    1
    2
    3
    4
    5
    6
    // \\b to get \b inside the string literal.
    String regex = "\\bJava\\b"; // 设置边界
    String replacementStr = "XML";
    String inputStr = "Java and Javascript";

    String newStr = inputStr.replaceAll(regex, replacementStr); // 字符串替换,替换单词 Java 为 XML
  • 边界匹配器

边界匹配 含义
^ 一行的开始
$ 一行的结束
\b 字边界
\B 非字边界
\A 输入的开始
\G 上一次匹配的结束
\z 输入的结束
\Z 输入的结束,但是对于最终终止符,如果有的话

5、分组

  • 可以通过括号将多个字符组合为一个单位。例如 (ab)。

  • 正则表达式中的每个组都有一个组号,从 1 开始。

    • Matcher 类中的方法 groupCount() 返回与 Matcher 实例相关联的模式中的组数。
    • 组 0 引用整个正则表达式和不由 groupCount() 方法报告。
  • 正则表达式中的每个左括号 ( 标记新组的开始。

  • 我们可以在正则表达式中返回引用组号。

    • 假设我们要匹配以 “abc” 开头,后跟 “xyz” 的文本,后跟 “abc”。
      • 我们可以写一个正则表达式为 “abcxyzabc”。
      • 我们可以使用反向引用将正则表达式重写为 “(abc)xyz \ 1”。\1 指第 1 组,即 (abc)。
      • \2 引用组2, \3 引用组3,依此类推。
  • 显示格式化的电话号码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    String regex = "\(\\d{3})(\\d{3})(\\d{4})\"; // 设置分组

    Pattern p = Pattern.compile(regex);
    String source = "1234567890, 12345, and 9876543210";

    Matcher m = p.matcher(source);

    while (m.find()) {
    System.out.println("Phone: " + m.group() + ", Formatted Phone: (" + m.group(1) + ") " + m.group(2) + "-" + m.group(3));
    }
  • 上面代码生成以下结果

    1
    2
    Phone: 1234567890, Formatted Phone: (123) 456-7890
    Phone: 9876543210, Formatted Phone: (987) 654-3210

6、查找/替换

  • 可以找到一个模式,并用一些文本替换,替换的文本取决于匹配的文本。

  • 在 Java 中,我们可以在 Matcher 类中使用以下两个方法来完成这个任务。

    1
    2
    Matcher appendReplacement(StringBuffer sb, String replacement)
    StringBuffer appendTail(StringBuffer sb)
  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /**
    在以下规则中将数字更改为文本:
    如果多于 5,更换多
    如果小于 5,更换少量
    如果是 1,替换为“只有一个”
    */

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

    String regex = "\\d+";
    StringBuffer sb = new StringBuffer();
    String replacementText = "";
    String matchedText = "";

    String text = "We have 7 tutorials for Java, 2 tutorials for Javascript and 1 tutorial for Oracle.";

    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(text);

    while (m.find()) {
    matchedText = m.group(); // 获取匹配字符
    int num = Integer.parseInt(matchedText); // 转为数字
    if (num == 1) {
    replacementText = "only one";
    } else if (num < 5) {
    replacementText = "a few";
    } else {
    replacementText = "many";
    }
    m.appendReplacement(sb, replacementText); // 替换为字符串,存储到 sb
    }

    m.appendTail(sb); // 结束

    System.out.println("Old Text: " + text);
    System.out.println("New Text: " + sb.toString());
文章目录
  1. 1. 前言
  2. 2. 1、正则表达式
    1. 2.1. 1.1 模式
    2. 2.2. 1.2 匹配
  3. 3. 2、元字符
  4. 4. 3、量词
  5. 5. 4、边界
  6. 6. 5、分组
  7. 7. 6、查找/替换
隐藏目录