活动公告

系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

Java开发者必学的正则表达式匹配技巧从基础语法到高级应用全面提升文本处理能力

SunJu_FaceMall

3万

主题

2720

科技点

3万

积分

执行版主

碾压王

积分
32881

塔罗立华奏

执行版主 发表于 2025-8-30 17:40:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

正则表达式是文本处理的强大工具,它提供了一种灵活、高效的方式来匹配、查找和替换文本。对于Java开发者而言,掌握正则表达式技巧可以大大提升文本处理能力,无论是数据验证、日志分析还是文本提取,正则表达式都能发挥重要作用。本文将从基础语法开始,逐步深入到高级应用,帮助Java开发者全面掌握正则表达式匹配技巧。

正则表达式基础语法

字符类

字符类是正则表达式中最基本的构建块,用于匹配特定类型的字符。
  1. // 示例:使用字符类
  2. import java.util.regex.*;
  3. public class CharacterClassExample {
  4.     public static void main(String[] args) {
  5.         // 匹配任意一个小写字母
  6.         System.out.println("a".matches("[a-z]")); // true
  7.         System.out.println("A".matches("[a-z]")); // false
  8.         
  9.         // 匹配任意一个字母(不区分大小写)
  10.         System.out.println("a".matches("[a-zA-Z]")); // true
  11.         System.out.println("Z".matches("[a-zA-Z]")); // true
  12.         
  13.         // 匹配任意一个数字
  14.         System.out.println("5".matches("[0-9]")); // true
  15.         System.out.println("a".matches("[0-9]")); // false
  16.         
  17.         // 匹配非数字
  18.         System.out.println("a".matches("[^0-9]")); // true
  19.         System.out.println("5".matches("[^0-9]")); // false
  20.         
  21.         // 预定义字符类
  22.         System.out.println("5".matches("\\d")); // true,等同于[0-9]
  23.         System.out.println("a".matches("\\D")); // true,等同于[^0-9]
  24.         System.out.println(" ".matches("\\s")); // true,空白字符
  25.         System.out.println("a".matches("\\S")); // true,非空白字符
  26.         System.out.println("a".matches("\\w")); // true,单词字符[a-zA-Z_0-9]
  27.         System.out.println("#".matches("\\W")); // true,非单词字符
  28.     }
  29. }
复制代码

量词

量词用于指定前面的字符或字符组出现的次数。
  1. // 示例:使用量词
  2. import java.util.regex.*;
  3. public class QuantifierExample {
  4.     public static void main(String[] args) {
  5.         // ? 表示0次或1次
  6.         System.out.println("color".matches("colou?r")); // true
  7.         System.out.println("colour".matches("colou?r")); // true
  8.         
  9.         // * 表示0次或多次
  10.         System.out.println("ab".matches("ab*c")); // false
  11.         System.out.println("ac".matches("ab*c")); // true
  12.         System.out.println("abbc".matches("ab*c")); // true
  13.         
  14.         // + 表示1次或多次
  15.         System.out.println("ac".matches("ab+c")); // false
  16.         System.out.println("abc".matches("ab+c")); // true
  17.         System.out.println("abbc".matches("ab+c")); // true
  18.         
  19.         // {n} 表示恰好n次
  20.         System.out.println("abbbbc".matches("ab{4}c")); // true
  21.         System.out.println("abbbc".matches("ab{4}c")); // false
  22.         
  23.         // {n,} 表示至少n次
  24.         System.out.println("abbbbc".matches("ab{3,}c")); // true
  25.         System.out.println("abbbc".matches("ab{3,}c")); // true
  26.         System.out.println("abbc".matches("ab{3,}c")); // false
  27.         
  28.         // {n,m} 表示至少n次,最多m次
  29.         System.out.println("abbbbc".matches("ab{3,5}c")); // true
  30.         System.out.println("abbbbbbbc".matches("ab{3,5}c")); // false
  31.     }
  32. }
复制代码

边界匹配

边界匹配用于匹配字符串的边界位置,而不是实际字符。
  1. // 示例:边界匹配
  2. import java.util.regex.*;
  3. public class BoundaryExample {
  4.     public static void main(String[] args) {
  5.         // ^ 匹配行开始
  6.         System.out.println("hello world".matches("^hello.*")); // true
  7.         System.out.println("say hello".matches("^hello.*")); // false
  8.         
  9.         // $ 匹配行结束
  10.         System.out.println("hello world".matches(".*world$")); // true
  11.         System.out.println("world hello".matches(".*world$")); // false
  12.         
  13.         // \b 匹配单词边界
  14.         Pattern pattern = Pattern.compile("\\bhello\\b");
  15.         Matcher matcher1 = pattern.matcher("hello world");
  16.         Matcher matcher2 = pattern.matcher("helloworld");
  17.         System.out.println(matcher1.find()); // true
  18.         System.out.println(matcher2.find()); // false
  19.         
  20.         // \B 匹配非单词边界
  21.         pattern = Pattern.compile("\\Bhello\\B");
  22.         matcher1 = pattern.matcher("helloworld");
  23.         matcher2 = pattern.matcher("hello world");
  24.         System.out.println(matcher1.find()); // true
  25.         System.out.println(matcher2.find()); // false
  26.     }
  27. }
复制代码

分组和捕获

分组使用括号()将多个字符组合为一个单元,并可以捕获匹配的内容。
  1. // 示例:分组和捕获
  2. import java.util.regex.*;
  3. public class GroupingExample {
  4.     public static void main(String[] args) {
  5.         // 基本分组
  6.         Pattern pattern = Pattern.compile("(\\d{3})-(\\d{2})-(\\d{4})");
  7.         Matcher matcher = pattern.matcher("123-45-6789");
  8.         
  9.         if (matcher.find()) {
  10.             System.out.println("完整匹配: " + matcher.group(0)); // 123-45-6789
  11.             System.out.println("第一组: " + matcher.group(1)); // 123
  12.             System.out.println("第二组: " + matcher.group(2)); // 45
  13.             System.out.println("第三组: " + matcher.group(3)); // 6789
  14.         }
  15.         
  16.         // 非捕获分组 (?:...)
  17.         pattern = Pattern.compile("(?:\\d{3})-(\\d{2})-(\\d{4})");
  18.         matcher = pattern.matcher("123-45-6789");
  19.         
  20.         if (matcher.find()) {
  21.             System.out.println("完整匹配: " + matcher.group(0)); // 123-45-6789
  22.             System.out.println("第一组: " + matcher.group(1)); // 45
  23.             System.out.println("第二组: " + matcher.group(2)); // 6789
  24.         }
  25.     }
  26. }
复制代码

Java中的正则表达式API

Pattern类

Pattern类是正则表达式的编译表示,它没有公共构造方法,必须通过调用其静态方法compile()来创建实例。
  1. // 示例:Pattern类的基本使用
  2. import java.util.regex.*;
  3. public class PatternExample {
  4.     public static void main(String[] args) {
  5.         // 编译正则表达式
  6.         Pattern pattern = Pattern.compile("\\d+");
  7.         
  8.         // 获取正则表达式字符串
  9.         System.out.println("正则表达式: " + pattern.pattern());
  10.         
  11.         // 分割字符串
  12.         String[] result = pattern.split("one1two2three3four4");
  13.         for (String s : result) {
  14.             System.out.println(s);
  15.         }
  16.         
  17.         // 带限制的分割
  18.         result = pattern.split("one1two2three3four4", 3);
  19.         for (String s : result) {
  20.             System.out.println(s);
  21.         }
  22.         
  23.         // 获取标志
  24.         Pattern caseInsensitivePattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
  25.         System.out.println("标志: " + caseInsensitivePattern.flags());
  26.     }
  27. }
复制代码

Matcher类

Matcher类是执行匹配操作的引擎,通过Pattern对象的matcher()方法创建。
  1. // 示例:Matcher类的基本使用
  2. import java.util.regex.*;
  3. public class MatcherExample {
  4.     public static void main(String[] args) {
  5.         Pattern pattern = Pattern.compile("\\d+");
  6.         Matcher matcher = pattern.matcher("one1two2three3four4");
  7.         
  8.         // 查找所有匹配
  9.         while (matcher.find()) {
  10.             System.out.println("找到匹配: " + matcher.group() +
  11.                              " 位置: " + matcher.start() +
  12.                              " 到 " + matcher.end());
  13.         }
  14.         
  15.         // 尝试匹配整个字符串
  16.         matcher.reset();
  17.         System.out.println("整个字符串匹配: " + matcher.matches());
  18.         
  19.         // 尝试匹配字符串开头
  20.         matcher.reset();
  21.         System.out.println("字符串开头匹配: " + matcher.lookingAt());
  22.         
  23.         // 替换操作
  24.         matcher.reset();
  25.         String result = matcher.replaceAll("#");
  26.         System.out.println("替换所有数字: " + result);
  27.         
  28.         matcher.reset();
  29.         result = matcher.replaceFirst("#");
  30.         System.out.println("替换第一个数字: " + result);
  31.     }
  32. }
复制代码

常用方法
  1. // 示例:正则表达式常用方法
  2. import java.util.regex.*;
  3. public class CommonMethodsExample {
  4.     public static void main(String[] args) {
  5.         // String类中的正则方法
  6.         String text = "Hello, this is a test string with 123 numbers.";
  7.         
  8.         // 检查是否匹配
  9.         System.out.println("字符串是否包含数字: " + text.matches(".*\\d+.*"));
  10.         
  11.         // 分割字符串
  12.         String[] words = text.split("\\s+");
  13.         System.out.println("分割后的单词数: " + words.length);
  14.         for (String word : words) {
  15.             System.out.println(word);
  16.         }
  17.         
  18.         // 替换
  19.         String replaced = text.replaceAll("\\s+", "_");
  20.         System.out.println("替换空格后: " + replaced);
  21.         
  22.         // 替换第一个匹配
  23.         replaced = text.replaceFirst("\\s+", "_");
  24.         System.out.println("替换第一个空格后: " + replaced);
  25.         
  26.         // 使用Pattern和Matcher进行更复杂的操作
  27.         Pattern pattern = Pattern.compile("\\b(\\w+)(\\s+)(\\1)\\b");
  28.         Matcher matcher = pattern.matcher("hello hello world world test");
  29.         
  30.         // 查找重复单词
  31.         while (matcher.find()) {
  32.             System.out.println("找到重复单词: " + matcher.group(1) +
  33.                              " 位置: " + matcher.start() +
  34.                              " 到 " + matcher.end());
  35.         }
  36.     }
  37. }
复制代码

实用匹配技巧

邮箱验证
  1. // 示例:邮箱验证
  2. import java.util.regex.*;
  3. public class EmailValidation {
  4.     public static void main(String[] args) {
  5.         // 基本邮箱验证正则
  6.         String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
  7.         
  8.         String[] testEmails = {
  9.             "user@example.com",
  10.             "user.name@example.com",
  11.             "user-name@example.com",
  12.             "user_name@example.com",
  13.             "user+name@example.com",
  14.             "user@sub.example.com",
  15.             "user@example.co.uk",
  16.             "invalid.email@com",
  17.             "@example.com",
  18.             "user@.com",
  19.             "user@example.",
  20.             "user..name@example.com"
  21.         };
  22.         
  23.         Pattern pattern = Pattern.compile(emailRegex);
  24.         
  25.         for (String email : testEmails) {
  26.             Matcher matcher = pattern.matcher(email);
  27.             System.out.println(email + " 是有效的邮箱: " + matcher.matches());
  28.         }
  29.     }
  30. }
复制代码

电话号码验证
  1. // 示例:电话号码验证
  2. import java.util.regex.*;
  3. public class PhoneNumberValidation {
  4.     public static void main(String[] args) {
  5.         // 美国电话号码格式验证
  6.         String usPhoneRegex = "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$";
  7.         
  8.         // 国际电话号码格式验证(简化版)
  9.         String internationalPhoneRegex = "^(\\+\\d{1,3}\\s?)?\\(?\\d{1,4}\\)?[\\s.-]?\\d{1,4}[\\s.-]?\\d{1,4}[\\s.-]?\\d{1,9}$";
  10.         
  11.         String[] testPhones = {
  12.             "1234567890",
  13.             "123-456-7890",
  14.             "(123) 456-7890",
  15.             "+1 123 456 7890",
  16.             "+1 (123) 456-7890",
  17.             "+44 20 7946 0958",
  18.             "+86 10 1234 5678",
  19.             "123",  // 无效
  20.             "12345678901234567890"  // 无效
  21.         };
  22.         
  23.         Pattern usPattern = Pattern.compile(usPhoneRegex);
  24.         Pattern internationalPattern = Pattern.compile(internationalPhoneRegex);
  25.         
  26.         System.out.println("美国电话号码验证:");
  27.         for (String phone : testPhones) {
  28.             Matcher matcher = usPattern.matcher(phone);
  29.             System.out.println(phone + " 是有效的美国电话号码: " + matcher.matches());
  30.         }
  31.         
  32.         System.out.println("\n国际电话号码验证:");
  33.         for (String phone : testPhones) {
  34.             Matcher matcher = internationalPattern.matcher(phone);
  35.             System.out.println(phone + " 是有效的国际电话号码: " + matcher.matches());
  36.         }
  37.     }
  38. }
复制代码

URL解析
  1. // 示例:URL解析
  2. import java.util.regex.*;
  3. public class URLParsing {
  4.     public static void main(String[] args) {
  5.         // URL解析正则表达式
  6.         String urlRegex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
  7.         
  8.         // 更详细的URL解析正则,用于提取各部分
  9.         String detailedUrlRegex = "^(https?|ftp|file)://([^/:]+)(?::(\\d+))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$";
  10.         
  11.         String[] testUrls = {
  12.             "https://www.example.com",
  13.             "http://example.com:8080/path/to/resource?query=value#fragment",
  14.             "ftp://files.example.com/documents",
  15.             "file:///C:/path/to/file.txt",
  16.             "invalid-url"
  17.         };
  18.         
  19.         Pattern pattern = Pattern.compile(urlRegex);
  20.         Pattern detailedPattern = Pattern.compile(detailedUrlRegex);
  21.         
  22.         System.out.println("URL有效性验证:");
  23.         for (String url : testUrls) {
  24.             Matcher matcher = pattern.matcher(url);
  25.             System.out.println(url + " 是有效的URL: " + matcher.matches());
  26.         }
  27.         
  28.         System.out.println("\n详细URL解析:");
  29.         for (String url : testUrls) {
  30.             Matcher matcher = detailedPattern.matcher(url);
  31.             if (matcher.matches()) {
  32.                 System.out.println("URL: " + url);
  33.                 System.out.println("协议: " + matcher.group(1));
  34.                 System.out.println("主机: " + matcher.group(2));
  35.                 System.out.println("端口: " + (matcher.group(3) != null ? matcher.group(3) : "默认"));
  36.                 System.out.println("路径: " + matcher.group(4));
  37.                 System.out.println("查询字符串: " + (matcher.group(5) != null ? matcher.group(5) : "无"));
  38.                 System.out.println("片段: " + (matcher.group(6) != null ? matcher.group(6) : "无"));
  39.                 System.out.println();
  40.             }
  41.         }
  42.     }
  43. }
复制代码

HTML标签处理
  1. // 示例:HTML标签处理
  2. import java.util.regex.*;
  3. public class HTMLTagProcessing {
  4.     public static void main(String[] args) {
  5.         String html = "<div class="example">\n" +
  6.                      "    <p>This is a <b>sample</b> text with <a href="https://example.com">links</a>.</p>\n" +
  7.                      "    <ul>\n" +
  8.                      "        <li>Item 1</li>\n" +
  9.                      "        <li>Item 2</li>\n" +
  10.                      "    </ul>\n" +
  11.                      "</div>";
  12.         
  13.         // 提取所有HTML标签
  14.         Pattern tagPattern = Pattern.compile("<[^>]+>");
  15.         Matcher tagMatcher = tagPattern.matcher(html);
  16.         
  17.         System.out.println("提取的HTML标签:");
  18.         while (tagMatcher.find()) {
  19.             System.out.println(tagMatcher.group());
  20.         }
  21.         
  22.         // 提取特定标签及其内容
  23.         Pattern pPattern = Pattern.compile("<p>(.*?)</p>", Pattern.DOTALL);
  24.         Matcher pMatcher = pPattern.matcher(html);
  25.         
  26.         System.out.println("\n<p>标签及其内容:");
  27.         while (pMatcher.find()) {
  28.             System.out.println(pMatcher.group(1));
  29.         }
  30.         
  31.         // 提取链接
  32.         Pattern linkPattern = Pattern.compile("<a\\s+href="([^"]+)"[^>]*>([^<]+)</a>");
  33.         Matcher linkMatcher = linkPattern.matcher(html);
  34.         
  35.         System.out.println("\n链接及其文本:");
  36.         while (linkMatcher.find()) {
  37.             System.out.println("URL: " + linkMatcher.group(1) + ", 文本: " + linkMatcher.group(2));
  38.         }
  39.         
  40.         // 移除所有HTML标签
  41.         String noHtml = html.replaceAll("<[^>]+>", "");
  42.         System.out.println("\n移除HTML标签后的文本:");
  43.         System.out.println(noHtml);
  44.     }
  45. }
复制代码

高级应用

贪婪与懒惰匹配
  1. // 示例:贪婪与懒惰匹配
  2. import java.util.regex.*;
  3. public class GreedyLazyMatching {
  4.     public static void main(String[] args) {
  5.         String text = "<div>内容1</div><div>内容2</div>";
  6.         
  7.         // 贪婪匹配(默认)
  8.         Pattern greedyPattern = Pattern.compile("<div>.*</div>");
  9.         Matcher greedyMatcher = greedyPattern.matcher(text);
  10.         
  11.         System.out.println("贪婪匹配:");
  12.         while (greedyMatcher.find()) {
  13.             System.out.println("匹配: " + greedyMatcher.group());
  14.         }
  15.         
  16.         // 懒惰匹配
  17.         Pattern lazyPattern = Pattern.compile("<div>.*?</div>");
  18.         Matcher lazyMatcher = lazyPattern.matcher(text);
  19.         
  20.         System.out.println("\n懒惰匹配:");
  21.         while (lazyMatcher.find()) {
  22.             System.out.println("匹配: " + lazyMatcher.group());
  23.         }
  24.         
  25.         // 贪婪匹配与量词
  26.         String numbers = "1234567890";
  27.         
  28.         // 贪婪匹配
  29.         Pattern greedyNumbers = Pattern.compile("\\d{5,8}");
  30.         Matcher greedyNumMatcher = greedyNumbers.matcher(numbers);
  31.         
  32.         System.out.println("\n贪婪匹配数字:");
  33.         if (greedyNumMatcher.find()) {
  34.             System.out.println("匹配: " + greedyNumMatcher.group()); // 匹配12345678
  35.         }
  36.         
  37.         // 懒惰匹配
  38.         Pattern lazyNumbers = Pattern.compile("\\d{5,8}?");
  39.         Matcher lazyNumMatcher = lazyNumbers.matcher(numbers);
  40.         
  41.         System.out.println("\n懒惰匹配数字:");
  42.         if (lazyNumMatcher.find()) {
  43.             System.out.println("匹配: " + lazyNumMatcher.group()); // 匹配12345
  44.         }
  45.     }
  46. }
复制代码

回溯控制
  1. // 示例:回溯控制
  2. import java.util.regex.*;
  3. public class BacktrackingControl {
  4.     public static void main(String[] args) {
  5.         // 原子组 (?>...)
  6.         String text = "123456";
  7.         
  8.         // 常规分组
  9.         Pattern normalPattern = Pattern.compile("(\\d+\\d+)");
  10.         Matcher normalMatcher = normalPattern.matcher(text);
  11.         
  12.         System.out.println("常规分组:");
  13.         if (normalMatcher.find()) {
  14.             System.out.println("匹配: " + normalMatcher.group());
  15.         }
  16.         
  17.         // 原子组
  18.         Pattern atomicPattern = Pattern.compile("(?>\\d+\\d+)");
  19.         Matcher atomicMatcher = atomicPattern.matcher(text);
  20.         
  21.         System.out.println("\n原子组:");
  22.         if (atomicMatcher.find()) {
  23.             System.out.println("匹配: " + atomicMatcher.group());
  24.         }
  25.         
  26.         // 占有量词 (++, *+, ?+, {m,n}+)
  27.         text = "123456";
  28.         
  29.         // 常规贪婪量词
  30.         Pattern greedyPattern = Pattern.compile("\\d++6");
  31.         Matcher greedyMatcher = greedyPattern.matcher(text);
  32.         
  33.         System.out.println("\n占有量词:");
  34.         if (greedyMatcher.find()) {
  35.             System.out.println("匹配: " + greedyMatcher.group());
  36.         } else {
  37.             System.out.println("没有匹配,因为\\d++占有了所有数字,没有回溯");
  38.         }
  39.         
  40.         // 常规贪婪量词(会回溯)
  41.         Pattern normalGreedyPattern = Pattern.compile("\\d+6");
  42.         Matcher normalGreedyMatcher = normalGreedyPattern.matcher(text);
  43.         
  44.         System.out.println("\n常规贪婪量词(会回溯):");
  45.         if (normalGreedyMatcher.find()) {
  46.             System.out.println("匹配: " + normalGreedyMatcher.group());
  47.         }
  48.     }
  49. }
复制代码

零宽断言
  1. // 示例:零宽断言
  2. import java.util.regex.*;
  3. public class ZeroWidthAssertions {
  4.     public static void main(String[] args) {
  5.         String text = "I have 100 dollars and 200 euros.";
  6.         
  7.         // 正向先行断言 (?=...)
  8.         Pattern positiveLookahead = Pattern.compile("\\d+(?=\\s*dollars)");
  9.         Matcher positiveMatcher = positiveLookahead.matcher(text);
  10.         
  11.         System.out.println("正向先行断言(查找dollars前的数字):");
  12.         while (positiveMatcher.find()) {
  13.             System.out.println("匹配: " + positiveMatcher.group());
  14.         }
  15.         
  16.         // 负向先行断言 (?!...)
  17.         Pattern negativeLookahead = Pattern.compile("\\d+(?!\\s*dollars)");
  18.         Matcher negativeMatcher = negativeLookahead.matcher(text);
  19.         
  20.         System.out.println("\n负向先行断言(查找不在dollars前的数字):");
  21.         while (negativeMatcher.find()) {
  22.             System.out.println("匹配: " + negativeMatcher.group());
  23.         }
  24.         
  25.         // 正向后行断言 (?<=...)
  26.         Pattern positiveLookbehind = Pattern.compile("(?<=I have\\s)\\d+");
  27.         Matcher positiveBehindMatcher = positiveLookbehind.matcher(text);
  28.         
  29.         System.out.println("\n正向后行断言(查找'I have'后的数字):");
  30.         while (positiveBehindMatcher.find()) {
  31.             System.out.println("匹配: " + positiveBehindMatcher.group());
  32.         }
  33.         
  34.         // 负向后行断言 (?<!...)
  35.         Pattern negativeLookbehind = Pattern.compile("(?<!I have\\s)\\d+");
  36.         Matcher negativeBehindMatcher = negativeLookbehind.matcher(text);
  37.         
  38.         System.out.println("\n负向后行断言(查找不在'I have'后的数字):");
  39.         while (negativeBehindMatcher.find()) {
  40.             System.out.println("匹配: " + negativeBehindMatcher.group());
  41.         }
  42.         
  43.         // 复杂示例:查找单词边界但不在特定单词后
  44.         String complexText = "The car is parked in the carpark.";
  45.         Pattern complexPattern = Pattern.compile("\\bcar\\b(?!park)");
  46.         Matcher complexMatcher = complexPattern.matcher(complexText);
  47.         
  48.         System.out.println("\n复杂示例:查找单词'car'但不后跟'park':");
  49.         while (complexMatcher.find()) {
  50.             System.out.println("匹配: " + complexMatcher.group() + " 位置: " + complexMatcher.start());
  51.         }
  52.     }
  53. }
复制代码

性能优化
  1. // 示例:正则表达式性能优化
  2. import java.util.regex.*;
  3. import java.util.concurrent.TimeUnit;
  4. public class PerformanceOptimization {
  5.     public static void main(String[] args) {
  6.         String longText = "This is a test string with many words. ".repeat(1000) + "The final word is end.";
  7.         
  8.         // 预编译正则表达式 vs 每次编译
  9.         String wordPattern = "\\bword\\b";
  10.         
  11.         // 不预编译
  12.         long startTime = System.nanoTime();
  13.         for (int i = 0; i < 1000; i++) {
  14.             Pattern pattern = Pattern.compile(wordPattern);
  15.             Matcher matcher = pattern.matcher(longText);
  16.             while (matcher.find()) {
  17.                 // 什么都不做,只是匹配
  18.             }
  19.         }
  20.         long endTime = System.nanoTime();
  21.         System.out.println("不预编译正则表达式耗时: " +
  22.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  23.         
  24.         // 预编译
  25.         Pattern precompiledPattern = Pattern.compile(wordPattern);
  26.         startTime = System.nanoTime();
  27.         for (int i = 0; i < 1000; i++) {
  28.             Matcher matcher = precompiledPattern.matcher(longText);
  29.             while (matcher.find()) {
  30.                 // 什么都不做,只是匹配
  31.             }
  32.         }
  33.         endTime = System.nanoTime();
  34.         System.out.println("预编译正则表达式耗时: " +
  35.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  36.         
  37.         // 使用具体字符类代替通配符
  38.         String testString = "abc123def456ghi789";
  39.         
  40.         // 使用通配符
  41.         Pattern dotPattern = Pattern.compile(".+");
  42.         startTime = System.nanoTime();
  43.         for (int i = 0; i < 10000; i++) {
  44.             Matcher matcher = dotPattern.matcher(testString);
  45.             matcher.matches();
  46.         }
  47.         endTime = System.nanoTime();
  48.         System.out.println("\n使用通配符耗时: " +
  49.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  50.         
  51.         // 使用具体字符类
  52.         Pattern specificPattern = Pattern.compile("[a-z0-9]+");
  53.         startTime = System.nanoTime();
  54.         for (int i = 0; i < 10000; i++) {
  55.             Matcher matcher = specificPattern.matcher(testString);
  56.             matcher.matches();
  57.         }
  58.         endTime = System.nanoTime();
  59.         System.out.println("使用具体字符类耗时: " +
  60.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  61.         
  62.         // 避免回溯
  63.         String backtrackTest = "<div>content</div><div>more content</div>";
  64.         
  65.         // 可能导致回溯的模式
  66.         Pattern backtrackPattern = Pattern.compile("<div>.*</div>");
  67.         startTime = System.nanoTime();
  68.         for (int i = 0; i < 10000; i++) {
  69.             Matcher matcher = backtrackPattern.matcher(backtrackTest);
  70.             matcher.find();
  71.         }
  72.         endTime = System.nanoTime();
  73.         System.out.println("\n可能导致回溯的模式耗时: " +
  74.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  75.         
  76.         // 避免回溯的模式
  77.         Pattern noBacktrackPattern = Pattern.compile("<div>[^<]*</div>");
  78.         startTime = System.nanoTime();
  79.         for (int i = 0; i < 10000; i++) {
  80.             Matcher matcher = noBacktrackPattern.matcher(backtrackTest);
  81.             matcher.find();
  82.         }
  83.         endTime = System.nanoTime();
  84.         System.out.println("避免回溯的模式耗时: " +
  85.                           TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  86.     }
  87. }
复制代码

常见问题与解决方案

处理特殊字符
  1. // 示例:处理正则表达式中的特殊字符
  2. import java.util.regex.*;
  3. public class SpecialCharacters {
  4.     public static void main(String[] args) {
  5.         // 需要转义的特殊字符
  6.         String specialChars = ".^$*+?{}[]\\|()";
  7.         
  8.         // 使用Pattern.quote()方法自动转义
  9.         String quotedText = Pattern.quote("1.5 * 2 = 3");
  10.         System.out.println("转义后的字符串: " + quotedText);
  11.         
  12.         // 匹配包含特殊字符的文本
  13.         String text = "The price is $19.99.";
  14.         String regex = "The price is \\$\\d+\\.\\d+\\.";
  15.         
  16.         Pattern pattern = Pattern.compile(regex);
  17.         Matcher matcher = pattern.matcher(text);
  18.         
  19.         if (matcher.matches()) {
  20.             System.out.println("匹配成功: " + matcher.group());
  21.         }
  22.         
  23.         // 使用Matcher.quoteReplacement()处理替换字符串中的特殊字符
  24.         String input = "Replace $1 with $2";
  25.         String replacement = Matcher.quoteReplacement("$$100 and $$200");
  26.         
  27.         Pattern replacePattern = Pattern.compile("\\$(\\d)");
  28.         Matcher replaceMatcher = replacePattern.matcher(input);
  29.         
  30.         String result = replaceMatcher.replaceAll(replacement);
  31.         System.out.println("替换结果: " + result);
  32.     }
  33. }
复制代码

多行模式与单行模式
  1. // 示例:多行模式与单行模式
  2. import java.util.regex.*;
  3. public class MultilineDotallModes {
  4.     public static void main(String[] args) {
  5.         String text = "First line\nSecond line\nThird line";
  6.         
  7.         // 默认模式(^和$匹配整个字符串的开始和结束)
  8.         Pattern defaultPattern = Pattern.compile("^First.*line$");
  9.         Matcher defaultMatcher = defaultPattern.matcher(text);
  10.         
  11.         System.out.println("默认模式匹配: " + defaultMatcher.find());
  12.         
  13.         // 多行模式(^和$匹配每行的开始和结束)
  14.         Pattern multilinePattern = Pattern.compile("^First.*line$", Pattern.MULTILINE);
  15.         Matcher multilineMatcher = multilinePattern.matcher(text);
  16.         
  17.         System.out.println("多行模式匹配: " + multilineMatcher.find());
  18.         
  19.         // 单行模式(.匹配包括换行符在内的所有字符)
  20.         String html = "<div>\nContent\n</div>";
  21.         
  22.         // 默认模式
  23.         Pattern defaultDotPattern = Pattern.compile("<div>.*</div>");
  24.         Matcher defaultDotMatcher = defaultDotPattern.matcher(html);
  25.         
  26.         System.out.println("\n默认模式匹配HTML: " + defaultDotMatcher.find());
  27.         
  28.         // 单行模式(DOTALL)
  29.         Pattern dotallPattern = Pattern.compile("<div>.*</div>", Pattern.DOTALL);
  30.         Matcher dotallMatcher = dotallPattern.matcher(html);
  31.         
  32.         System.out.println("单行模式匹配HTML: " + dotallMatcher.find());
  33.         
  34.         // 组合使用多行和单行模式
  35.         String complexText = "Start\nLine 1\nLine 2\nEnd";
  36.         
  37.         Pattern combinedPattern = Pattern.compile("^Start.*End$", Pattern.MULTILINE | Pattern.DOTALL);
  38.         Matcher combinedMatcher = combinedPattern.matcher(complexText);
  39.         
  40.         System.out.println("\n组合模式匹配: " + combinedMatcher.find());
  41.     }
  42. }
复制代码

Unicode支持
  1. // 示例:Unicode支持
  2. import java.util.regex.*;
  3. public class UnicodeSupport {
  4.     public static void main(String[] args) {
  5.         // Unicode字符匹配
  6.         String text = "English 中文 日本語 한국어 Español Français";
  7.         
  8.         // 匹配中文字符
  9.         Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fff]+");
  10.         Matcher chineseMatcher = chinesePattern.matcher(text);
  11.         
  12.         System.out.println("中文字符:");
  13.         while (chineseMatcher.find()) {
  14.             System.out.println(chineseMatcher.group());
  15.         }
  16.         
  17.         // 匹配日文字符(平假名和片假名)
  18.         Pattern japanesePattern = Pattern.compile("[\\u3040-\\u309f\\u30a0-\\u30ff]+");
  19.         Matcher japaneseMatcher = japanesePattern.matcher(text);
  20.         
  21.         System.out.println("\n日文字符:");
  22.         while (japaneseMatcher.find()) {
  23.             System.out.println(japaneseMatcher.group());
  24.         }
  25.         
  26.         // 匹配韩文字符
  27.         Pattern koreanPattern = Pattern.compile("[\\uac00-\\ud7af]+");
  28.         Matcher koreanMatcher = koreanPattern.matcher(text);
  29.         
  30.         System.out.println("\n韩文字符:");
  31.         while (koreanMatcher.find()) {
  32.             System.out.println(koreanMatcher.group());
  33.         }
  34.         
  35.         // 使用Unicode属性(需要UNICODE_CHARACTER_CLASS标志)
  36.         Pattern letterPattern = Pattern.compile("\\p{L}+", Pattern.UNICODE_CHARACTER_CLASS);
  37.         Matcher letterMatcher = letterPattern.matcher(text);
  38.         
  39.         System.out.println("\n所有字母(使用Unicode属性):");
  40.         while (letterMatcher.find()) {
  41.             System.out.println(letterMatcher.group());
  42.         }
  43.         
  44.         // 使用Unicode脚本
  45.         Pattern hanPattern = Pattern.compile("\\p{Han}+", Pattern.UNICODE_CHARACTER_CLASS);
  46.         Matcher hanMatcher = hanPattern.matcher(text);
  47.         
  48.         System.out.println("\n汉字(使用Unicode脚本):");
  49.         while (hanMatcher.find()) {
  50.             System.out.println(hanMatcher.group());
  51.         }
  52.     }
  53. }
复制代码

最佳实践

可读性与维护性
  1. // 示例:提高正则表达式的可读性与维护性
  2. import java.util.regex.*;
  3. public class ReadabilityAndMaintainability {
  4.     public static void main(String[] args) {
  5.         // 复杂的正则表达式(难以阅读和维护)
  6.         String complexRegex = "^(https?|ftp)://(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+(?:[A-Z]{2,6}\\.?|[A-Z0-9-]{2,}\\.?))(?::\\d{2,5})?(?:/[^\s]*)?$";
  7.         
  8.         // 使用注释和构建块提高可读性
  9.         String protocol = "(https?|ftp)";
  10.         String domain = "(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+(?:[A-Z]{2,6}\\.?|[A-Z0-9-]{2,}\\.?))";
  11.         String port = "(?::\\d{2,5})?";
  12.         String path = "(?:/[^\s]*)?";
  13.         
  14.         String readableRegex = "^" + protocol + "://" + domain + port + path + "$";
  15.         
  16.         // 使用COMMENTS标志允许正则表达式中的空白和注释
  17.         String commentedRegex =
  18.             "^" + protocol + "://" +  // 协议部分
  19.             domain +                  // 域名部分
  20.             port +                    // 端口部分(可选)
  21.             path + "$";               // 路径部分(可选)
  22.         
  23.         Pattern pattern = Pattern.compile(commentedRegex, Pattern.CASE_INSENSITIVE | Pattern.COMMENTS);
  24.         
  25.         String[] testUrls = {
  26.             "https://www.example.com",
  27.             "http://subdomain.example.com:8080/path/to/resource",
  28.             "ftp://files.example.com/documents/"
  29.         };
  30.         
  31.         for (String url : testUrls) {
  32.             Matcher matcher = pattern.matcher(url);
  33.             System.out.println(url + " 是有效的URL: " + matcher.matches());
  34.         }
  35.         
  36.         // 使用常量存储常用的正则表达式
  37.         class RegexPatterns {
  38.             public static final String EMAIL = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
  39.             public static final String US_PHONE = "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$";
  40.             public static final String URL = "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$";
  41.         }
  42.         
  43.         Pattern emailPattern = Pattern.compile(RegexPatterns.EMAIL);
  44.         System.out.println("\n使用常量存储的正则表达式:");
  45.         System.out.println("test@example.com 是有效的邮箱: " + emailPattern.matcher("test@example.com").matches());
  46.     }
  47. }
复制代码

测试正则表达式
  1. // 示例:测试正则表达式
  2. import java.util.regex.*;
  3. import java.util.*;
  4. public class TestingRegex {
  5.     public static void main(String[] args) {
  6.         // 创建测试用例
  7.         List<RegexTestCase> testCases = new ArrayList<>();
  8.         
  9.         // 邮箱验证测试用例
  10.         testCases.add(new RegexTestCase(
  11.             "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$",
  12.             Arrays.asList("user@example.com", "user.name@example.com", "user+name@example.com"),
  13.             Arrays.asList("invalid.email@com", "@example.com", "user@.com")
  14.         ));
  15.         
  16.         // 电话号码验证测试用例
  17.         testCases.add(new RegexTestCase(
  18.             "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$",
  19.             Arrays.asList("1234567890", "123-456-7890", "(123) 456-7890", "+1 123 456 7890"),
  20.             Arrays.asList("123", "12345678901234567890", "abc-def-ghij")
  21.         ));
  22.         
  23.         // 运行测试
  24.         for (RegexTestCase testCase : testCases) {
  25.             System.out.println("测试正则表达式: " + testCase.regex);
  26.             Pattern pattern = Pattern.compile(testCase.regex);
  27.             
  28.             System.out.println("有效测试用例:");
  29.             for (String validCase : testCase.validCases) {
  30.                 boolean result = pattern.matcher(validCase).matches();
  31.                 System.out.println("  " + validCase + " -> " + (result ? "通过" : "失败"));
  32.             }
  33.             
  34.             System.out.println("无效测试用例:");
  35.             for (String invalidCase : testCase.invalidCases) {
  36.                 boolean result = pattern.matcher(invalidCase).matches();
  37.                 System.out.println("  " + invalidCase + " -> " + (result ? "失败" : "通过"));
  38.             }
  39.             
  40.             System.out.println();
  41.         }
  42.     }
  43.    
  44.     // 测试用例类
  45.     static class RegexTestCase {
  46.         String regex;
  47.         List<String> validCases;
  48.         List<String> invalidCases;
  49.         
  50.         RegexTestCase(String regex, List<String> validCases, List<String> invalidCases) {
  51.             this.regex = regex;
  52.             this.validCases = validCases;
  53.             this.invalidCases = invalidCases;
  54.         }
  55.     }
  56. }
复制代码

性能考虑
  1. // 示例:正则表达式性能考虑
  2. import java.util.regex.*;
  3. import java.util.concurrent.TimeUnit;
  4. public class PerformanceConsiderations {
  5.     public static void main(String[] args) {
  6.         // 测试文本
  7.         String text = "This is a test string with many words. ".repeat(10000);
  8.         
  9.         // 1. 预编译正则表达式
  10.         System.out.println("1. 预编译正则表达式:");
  11.         
  12.         // 不预编译
  13.         long startTime = System.nanoTime();
  14.         for (int i = 0; i < 100; i++) {
  15.             Pattern pattern = Pattern.compile("\\bword\\b");
  16.             Matcher matcher = pattern.matcher(text);
  17.             while (matcher.find()) {
  18.                 // 什么都不做,只是匹配
  19.             }
  20.         }
  21.         long endTime = System.nanoTime();
  22.         System.out.println("不预编译耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  23.         
  24.         // 预编译
  25.         Pattern precompiledPattern = Pattern.compile("\\bword\\b");
  26.         startTime = System.nanoTime();
  27.         for (int i = 0; i < 100; i++) {
  28.             Matcher matcher = precompiledPattern.matcher(text);
  29.             while (matcher.find()) {
  30.                 // 什么都不做,只是匹配
  31.             }
  32.         }
  33.         endTime = System.nanoTime();
  34.         System.out.println("预编译耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  35.         
  36.         // 2. 使用适当的量词
  37.         System.out.println("\n2. 使用适当的量词:");
  38.         
  39.         String testString = "a".repeat(1000) + "b";
  40.         
  41.         // 使用贪婪量词
  42.         Pattern greedyPattern = Pattern.compile("a+b");
  43.         startTime = System.nanoTime();
  44.         for (int i = 0; i < 1000; i++) {
  45.             Matcher matcher = greedyPattern.matcher(testString);
  46.             matcher.find();
  47.         }
  48.         endTime = System.nanoTime();
  49.         System.out.println("贪婪量词耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  50.         
  51.         // 使用占有量词
  52.         Pattern possessivePattern = Pattern.compile("a++b");
  53.         startTime = System.nanoTime();
  54.         for (int i = 0; i < 1000; i++) {
  55.             Matcher matcher = possessivePattern.matcher(testString);
  56.             matcher.find();
  57.         }
  58.         endTime = System.nanoTime();
  59.         System.out.println("占有量词耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  60.         
  61.         // 3. 避免回溯
  62.         System.out.println("\n3. 避免回溯:");
  63.         
  64.         String html = "<div>content</div>".repeat(100);
  65.         
  66.         // 可能导致回溯的模式
  67.         Pattern backtrackPattern = Pattern.compile("<div>.*</div>");
  68.         startTime = System.nanoTime();
  69.         for (int i = 0; i < 100; i++) {
  70.             Matcher matcher = backtrackPattern.matcher(html);
  71.             while (matcher.find()) {
  72.                 // 什么都不做,只是匹配
  73.             }
  74.         }
  75.         endTime = System.nanoTime();
  76.         System.out.println("可能导致回溯的模式耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  77.         
  78.         // 避免回溯的模式
  79.         Pattern noBacktrackPattern = Pattern.compile("<div>[^<]*</div>");
  80.         startTime = System.nanoTime();
  81.         for (int i = 0; i < 100; i++) {
  82.             Matcher matcher = noBacktrackPattern.matcher(html);
  83.             while (matcher.find()) {
  84.                 // 什么都不做,只是匹配
  85.             }
  86.         }
  87.         endTime = System.nanoTime();
  88.         System.out.println("避免回溯的模式耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  89.         
  90.         // 4. 使用String方法替代正则表达式
  91.         System.out.println("\n4. 使用String方法替代正则表达式:");
  92.         
  93.         String simpleText = "Hello, world!";
  94.         
  95.         // 使用正则表达式
  96.         Pattern simplePattern = Pattern.compile("Hello");
  97.         startTime = System.nanoTime();
  98.         for (int i = 0; i < 10000; i++) {
  99.             Matcher matcher = simplePattern.matcher(simpleText);
  100.             matcher.find();
  101.         }
  102.         endTime = System.nanoTime();
  103.         System.out.println("使用正则表达式耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  104.         
  105.         // 使用String.contains
  106.         startTime = System.nanoTime();
  107.         for (int i = 0; i < 10000; i++) {
  108.             simpleText.contains("Hello");
  109.         }
  110.         endTime = System.nanoTime();
  111.         System.out.println("使用String.contains耗时: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
  112.     }
  113. }
复制代码

总结

正则表达式是Java开发者必备的技能之一,它提供了强大的文本处理能力。本文从基础语法开始,逐步介绍了正则表达式的各种高级应用,包括:

1. 基础语法:字符类、量词、边界匹配和分组捕获是构建正则表达式的基础。
2. Java API:Pattern和Matcher类是Java中处理正则表达式的核心,掌握它们的使用方法是关键。
3. 实用技巧:通过邮箱验证、电话号码验证、URL解析和HTML标签处理等实际例子,展示了正则表达式的实际应用。
4. 高级应用:贪婪与懒惰匹配、回溯控制、零宽断言和性能优化等高级技巧可以帮助开发者解决更复杂的问题。
5. 最佳实践:提高正则表达式的可读性和维护性,进行充分的测试,并考虑性能因素,是编写高质量正则表达式的关键。

通过掌握这些技巧,Java开发者可以大大提升文本处理能力,更高效地解决各种文本匹配和处理问题。正则表达式虽然强大,但也需要谨慎使用,避免过度复杂的表达式,以免影响代码的可读性和性能。希望本文能够帮助Java开发者全面掌握正则表达式,并在实际开发中灵活应用。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则