什么是正则表达式?
正则表达式(Regular Expression,简称 Regex) 是用于匹配、搜索、替换字符串的强大工具。它通过特定的模式(Pattern),匹配文本中的特定字符组合,广泛应用于数据验证、文本处理、爬虫、日志分析等场景。
基本语法
| 字符 | 
描述 | 
| ^ | 
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 | 
| $ | 
匹配输入字符串的结束位置。如果设置了 RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。 | 
| * | 
匹配前面的子表达式零次或多次。例如:‘zo*’ 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 | 
| + | 
匹配前面的子表达式一次或多次。例如:‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 | 
| ? | 
匹配前面的子表达式零次或一次。例如:‘do(es)?’ 可以匹配 “do” 或 “does” 中的 “do” 。? 等价于 {0,1}。 | 
| () | 
标记一个子表达式的开始和结束位置。 | 
| {n} | 
n 是一个非负整数,匹配确定的 n 次。例如:‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 | 
| {n,} | 
n 是一个非负整数,至少匹配 n 次。例如:‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’,‘o{0,}’ 则等价于 ‘o*’。 | 
| {n, m} | 
m 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次。例如:‘o{1,3}’ 将匹配 “fooooood” 中的前三个 o,‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 | 
| x|y | 
匹配 x 或 y。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。 | 
| [xyz] | 
字符集合,匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 | 
| [^xyz] | 
负值字符集合,匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。 | 
| [a-z] | 
字符范围,匹配指定范围内的任意字符。例如,‘[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 | 
| [^a-z] | 
负值字符范围,匹配任何不在指定范围内的任意字符。例如,‘[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。 | 
| \d | 
匹配一个数字字符。等价于 [0-9]。 | 
| \D | 
匹配一个非数字字符。等价于 [^0-9]。 | 
| \f | 
匹配一个换页符。 | 
| \n | 
匹配一个换行符。 | 
| \r | 
匹配一个回车符。 | 
| \s | 
匹配任何空白字符,包括空格、制表符、换页符等等。 | 
| \S | 
匹配任何非空白字符。 | 
| \t | 
匹配一个制表符。 | 
| \v | 
匹配一个垂直制表符。 | 
| \w | 
匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]'。 | 
| \W | 
匹配任何非单词字符。 | 
常用实例
- 匹配字符
 
| 表达式 | 
匹配内容 | 
示例 | 
. | 
任意单个字符 | 
a.b 可匹配 acb | 
\d | 
数字 [0-9] | 
\d\d 可匹配 12 | 
\D | 
非数字 [^\d] | 
\D 可匹配 a | 
\w | 
字母、数字、下划线 [a-zA-Z0-9_] | 
\w+ 可匹配 abc123 | 
\W | 
非字母、数字、下划线 | 
\W 可匹配 @ | 
\s | 
空格(包含 \t, \n, \r) | 
\s+ 可匹配 "   " | 
\S | 
非空格字符 | 
\S 可匹配 a | 
- 量词(重复次数)
 
| 表达式 | 
匹配次数 | 
示例 | 
* | 
0 次或多次 | 
a* 可匹配 ""、a、aaaa | 
+ | 
1 次或多次 | 
a+ 可匹配 a、aaaa | 
? | 
0 次或 1 次 | 
a? 可匹配 ""、a | 
{n} | 
恰好 n 次 | 
a{3} 可匹配 aaa | 
{n,} | 
至少 n 次 | 
a{2,} 可匹配 aa、aaaaa | 
{n, m} | 
n 到 m 次 | 
a{2,4} 可匹配 aa、aaa、aaaa | 
- 边界匹配
 
| 表达式 | 
匹配位置 | 
示例 | 
^ | 
匹配字符串开头 | 
^abc 匹配 "abc123" 但不匹配 "123abc" | 
$ | 
匹配字符串结尾 | 
xyz$ 匹配 "123xyz" 但不匹配 "xyz123" | 
\b | 
匹配单词边界 | 
\bword\b 仅匹配 " word " 而不匹配 "word123" | 
\B | 
非单词边界 | 
\Bword\B 匹配 "awordb" 但不匹配 " word " | 
- 分组
 
| 表达式 | 
作用 | 
示例 | 
() | 
分组 | 
(abc)+ 可匹配 "abcabc" | 
(?:...) | 
非捕获分组 | 
(?: abc)+ 仅用于匹配,不保存 | 
Java 使用
- 直接使用字符串的 matches() 方法
 
1 2 3 4 5 6 7 8 9 10 11
   | public class RegexDemo {          public static void main(String[] args) {         String text = "abc123";         boolean isMatch = text.matches("[a-zA-Z]+\\d+");         System.out.println(isMatch);          text = "abc123aa";         isMatch = text.matches("[a-zA-Z]+\\d+");         System.out.println(isMatch);      } }
  | 
 
注意:matches() 方法必须匹配整个字符串,如果只匹配部分,则返回 false。
- 使用 Pattern 和 Matcher
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | public class RegexExample {          public static void main(String[] args) {         String text = "My email is test@example.com";         String pattern = "[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\\.[a-zA-Z]{2,}";
          Pattern regex = Pattern.compile(pattern);         Matcher matcher = regex.matcher(text);
          if (matcher.find()) {             System.out.println("匹配的邮箱: " + matcher.group());          }     } }
  | 
 
使用案例
- 验证邮箱格式
 
1 2 3 4 5 6
   | public static boolean isValidEmail(String email) {     String regex = "^[\\w.-]+@[a-zA-Z\\d.-]+\\.[a-zA-Z]{2,6}$";     return email.matches(regex); }
  System.out.println(isValidEmail("test@example.com")); 
  | 
 
- 提取手机号码
 
1 2 3 4 5 6 7 8 9
   | public static void extractPhoneNumbers(String text) {     String regex = "\\b1[3-9]\\d{9}\\b";      Pattern pattern = Pattern.compile(regex);     Matcher matcher = pattern.matcher(text);     while (matcher.find()) {         System.out.println("手机号: " + matcher.group());     } }
 
  | 
 
- 替换敏感词
 
1 2 3 4 5 6
   | public static String replaceSensitiveWords(String input) {     String regex = "(?i)badword|敏感词";      return input.replaceAll(regex, "***"); }
 
 
  | 
 
- 分割字符串
 
1 2 3
   | String str = "apple,banana,orange"; String[] fruits = str.split("\\s*,\\s*"); 
 
   | 
 
- 提取 URL 中的域名
 
1 2 3 4 5 6 7 8 9 10 11
   | public static String extractDomain(String url) {     String regex = "^(https?://)?([\\w.-]+)(/.*)?$";     Pattern pattern = Pattern.compile(regex);     Matcher matcher = pattern.matcher(url);     if (matcher.find()) {         return matcher.group(2);      }     return null; }
 
 
  | 
 
- 分组捕获
 
使用 () 分组,通过 matcher.group(n) 获取:
1 2 3 4 5 6
   | Pattern p = Pattern.compile("(\\d{3})-(\\d{4})"); Matcher m = p.matcher("010-1234"); if (m.matches()) {     System.out.println("区号: " + m.group(1));      System.out.println("号码: " + m.group(2));  }
  | 
 
修饰符
| 修饰符 | 
含义 | 
描述 | 
| i | 
ignore - 不区分大小写 | 
将匹配设置为不区分大小写,搜索时不区分大小写:A 和 a 没有区别。 | 
| g | 
global - 全局匹配 | 
查找所有的匹配项 | 
| m | 
multiline - 多行匹配 | 
使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。 | 
| s | 
特殊字符圆点 . 中包含换行符 \n | 
默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, .中包含换行符 \n。 | 
JS 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | var str="Google runoob taobao runoob";  var n1=str.match(/runoob/);    var n2=str.match(/runoob/g);  
 
  var str="Google runoob taobao RUNoob";  var n1=str.match(/runoob/g);    var n2=str.match(/runoob/gi);  
 
  var str="runoobgoogle\ntaobao\nrunoobweibo"; var n1=str.match(/^runoob/g);    var n2=str.match(/^runoob/gm);  
 
  var str="google\nrunoob\ntaobao"; var n1=str.match(/google./);    var n2=str.match(/runoob./s);  
   | 
 
Java 使用
| 修饰符 | 
值 | 
作用 | 
| Pattern.CASE_INSENSITIVE | 
(?i) | 
忽略大小写,如 “hello” 可匹配 “HELLO” | 
| Pattern.MULTILINE | 
(?m) | 
多行匹配,^$ 匹配每行的开头和结尾 | 
| Pattern.DOTALL | 
(?s) | 
让 . 匹配换行符 \n | 
| Pattern.UNICODE_CASE | 
(?u) | 
Unicode 大小写匹配(配合 CASE_INSENSITIVE) | 
| Pattern.COMMENTS | 
(?x) | 
忽略正则中的空格和注释 | 
| Pattern.UNICODE_CHARACTER_CLASS | 
(?U) | 
使用 Unicode 字符类别 | 
- 忽略大小写
 
1 2 3 4 5 6 7 8 9
   | Pattern pattern = Pattern.compile("hello", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher("HELLO"); System.out.println(matcher.find()); 
 
  String regex = "(?i)hello";  pattern = Pattern.compile(regex); matcher = pattern.matcher("HELLO"); System.out.println(matcher.find()); 
  | 
 
- 多行匹配
 
默认 ^ 只匹配整个字符串开头,$ 只匹配结尾。使用 MULTILINE 后,^ 和 $ 适用于每行
1 2 3 4 5
   | String text = "Hello\nJava"; Pattern pattern = Pattern.compile("^Java", Pattern.MULTILINE);
  Matcher matcher = pattern.matcher(text); System.out.println(matcher.find()); 
   | 
 
- 让 
. 匹配换行符 \n 
默认情况下,. 不会匹配换行符,使用 DOTALL 使 . 能匹配换行符
1 2 3 4 5 6 7
   | String text = "Hello\nJava"; Pattern pattern = Pattern.compile("Hello.Java"); System.out.println(pattern.matcher(text).find()); 
  pattern = Pattern.compile("Hello.Java", Pattern.DOTALL);
  System.out.println(pattern.matcher(text).find()); 
   | 
 
- 组合多个修饰符
 
可以使用按位或 |  组合多个修饰符
1 2
   | Pattern pattern = Pattern.compile("hello", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
 
  | 
 
运算符优先级
| 运算符 | 
描述 | 
| \ | 
转义符 | 
| (), (?:), (?=), [] | 
圆括号和方括号 | 
| *, +, ?, {n}, {n,}, {n, m} | 
限定符 | 
| ^, $, \任何元字符、任何字符 | 
定位点和序列(即:位置和顺序) | 
| | | 
替换,“或” 操作  字符具有高于替换运算符的优先级,使得 “m|food” 匹配 “m” 或 “food”。若要匹配 “mood” 或 “food”,请使用括号创建子表达式,从而产生 “(m|f)ood”。 |