正则匹配
基本使用
java.util.regex 包主要包括以下三个类:
- Pattern 类
正则表达式的编译表示。没有公共构造方法,必须首先调用其公共静态编译方法获得 Pattern 对象。
- Matcher 类
对输入字符串进行解释和匹配操作的引擎。没有公共构造方法,需要调用 Pattern 对象的 matcher 方法获得 Matcher 对象。
- PatternSyntaxException 类
非强制异常类,表示正则表达式模式中的语法错误。
import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexMatches { public static void main( String args[] ) { Pattern p = Pattern.compile("abc"); // 编译正则表达式 Matcher matcher = p.matcher("abcdefg"); // 放入字符串中匹配 System.out.println(matcher.lookingAt()); // 是否存在子串匹配 true System.out.println(matcher.matches()); // 是否完全匹配 false } }Copy to clipboardErrorCopied 复制代码
正则表达式
我们可以通过使用特殊符号,让一个正则表达式能够匹配多种符合要求的字符串。
表意符号
.
表示任意字符
在 Java 中,正则表达式编译需要再经过一次转义。因此 \
才表示插入一个正则表达式的反斜线!
\d
表示一位数字\\
表示一个反斜杠
字符集
x|y
匹配 x 或 y[abc]
匹配括号中任意单个字符[^abc]
匹配除括号中的任意单个字符[a-zA-Z]
匹配任意单个字母[a-z&&[^def]]
除 def 外的任意单个字母
字符串匹配
通过 ?
、*
、+
符号,我们可以对指定类型的字符串进行匹配。
贪婪模式 | 饥饿模式 | 独占模式 | 结果 |
X? | X?? | X?+ | 匹配0或1次 |
X* | X*? | X*+ | 匹配0次或多次 |
X+ | X+? | X++ | 匹配1次或多次 |
X{n} | X{n}? | X{n}+ | 匹配n次 |
X{m,n} | X{m,n}? | X{m,n}+ | 匹配m-n次 |
在匹配字符串时,同一个正则表达式可能会在在字符串中匹配到多种结果。Java 提供了以下三种方式供开发者选择:
- 贪婪模式 (默认)尽可能匹配长字符串。
- 饥饿模式 (?)尽可能匹配短字符串。
- 独占模式 (+)尽可能匹配长字符串,不成功会结束匹配而不回溯。
捕获组
普通捕获组
我们可以在正则表达式中同时捕获多个结果,最终以 group 的形式呈现。
- matcher.group(0) 完全匹配整个正则表达式。
- matcher.group(1-n) 从左到右分别记录正则表达式中 n 个括号内的结果。
public class RegexMatches { public static void main( String args[] ) { String regex = "(\d{4})-((\d{2})-(\d{2}))" Pattern p = Pattern.compile(regex); // 编译正则表达式 Matcher matcher = p.matcher("2020-10-25"); // 放入字符串 matcher.find(); // 执行匹配 System.out.printf(matcher.group(0)); // 2020-10-25 System.out.printf(matcher.group(1)); // 2020 System.out.printf(matcher.group(2)); // 10-25 System.out.printf(matcher.group(3)); // 10 System.out.printf(matcher.group(4)); // 25 } }Copy to clipboardErrorCopied 复制代码
命名捕获组
我们可以通过 (?<Name>Expression)
对括号内容就行命名,并通过名称获取括号内的匹配结果。
public class RegexMatches { public static void main( String args[] ) { String regex = "(?<year>\d{4})-(?<md>(?<month>\d{2})-(?<date>\d{2}))"; Pattern p = Pattern.compile(regex); // 编译正则表达式 Matcher matcher = p.matcher("2020-10-25"); // 放入字符串中匹配 matcher.find(); // 执行匹配 System.out.printf(matcher.group("year")); // 2020 System.out.printf(matcher.group("md")); // 10-25 System.out.printf(matcher.group("month")); // 10 System.out.printf(matcher.group("date")); // 25 } }Copy to clipboardErrorCopied 复制代码
非捕获组
我们可以通过 (?:Expression)
对组不进行捕获。
(?=pattern)
例如,'Windows (?=95|98|NT|2000)' 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。
预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern)
如 'Windows (?!95|98|NT|2000)' 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。
预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。