JavaSE正则表达式完全指南

一、正则表达式基础语法

1. 元字符速查表

元字符说明示例
.匹配任意单个字符a.c → abc, a&c
\d数字字符 [0-9]\d\d → 12, 45
\D非数字字符 [^0-9]\D\D → ab, #$
\w单词字符 [a-zA-Z0-9_]\w+ → hello, A1_
\W非单词字符 [^\w]\W → @, 空格
\s空白字符 [ \t\n\x0B\f\r]\s+ → ” “, “\n”
\S非空白字符 [^\s]\S\S → ab, 12
^行首^Java → Java开头
$行尾end$ → 以end结尾
图片[1]_JavaSE正则表达式完全指南_知途无界

2. 量词表达式

量词说明示例
*0次或多次a*b → b, aab
+1次或多次a+b → ab, aaab
?0次或1次a?b → b, ab
{n}恰好n次a{2} → aa
{n,}至少n次a{2,} → aaa
{n,m}n到m次a{2,4} → aaa

二、Java正则API核心类

1. Pattern类

// 编译正则表达式(线程安全)
Pattern pattern = Pattern.compile("\\d{3}-\\d{4}");

// 常用方法
Matcher matcher = pattern.matcher("123-4567");
boolean matches = pattern.matches("\\d+", "123"); // 静态快捷方法

2. Matcher类

Matcher matcher = Pattern.compile("\\d+").matcher("a1b23c456");

// 查找方法
while (matcher.find()) {
    System.out.println(matcher.group()); // 1, 23, 456
}

// 其他重要方法
boolean matches = matcher.matches(); // 全匹配
boolean lookingAt = matcher.lookingAt(); // 前缀匹配
String replaced = matcher.replaceAll("#"); // a#b#c#

三、字符串操作中的正则

1. String类正则方法

// 分割字符串
String[] parts = "a,b;c".split("[,;]"); // ["a", "b", "c"]

// 替换操作
String result = "a1b2c3".replaceAll("\\d", "#"); // a#b#c#

// 匹配检查
boolean isValid = "123-4567".matches("\\d{3}-\\d{4}"); // true

2. 分组捕获示例

Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2023-05-15");

if (m.matches()) {
    String year = m.group(1);  // 2023
    String month = m.group(2);  // 05
    String day = m.group(3);    // 15
}

四、高级匹配技巧

1. 贪婪与懒惰模式

模式说明示例
贪婪默认模式,尽可能多匹配a.*b → “aabab”中匹配整个字符串
懒惰加?后缀,尽可能少匹配a.*?b → “aabab”中匹配”aab”和”ab”
// 贪婪匹配
Matcher greedy = Pattern.compile("a.*b").matcher("aabab");
greedy.find(); // 匹配整个"aabab"

// 懒惰匹配
Matcher lazy = Pattern.compile("a.*?b").matcher("aabab");
lazy.find(); // 匹配"aab"
lazy.find(); // 匹配"ab"

2. 零宽断言

断言类型语法说明
正向先行断言(?=exp)匹配后面是exp的位置
负向先行断言(?!exp)匹配后面不是exp的位置
正向后行断言(?<=exp)匹配前面是exp的位置
负向后行断言(?<!exp)匹配前面不是exp的位置
// 提取价格数字
Pattern pricePattern = Pattern.compile("(?<=\\$)\\d+");
Matcher m = pricePattern.matcher("Price: $100, $200");
while (m.find()) {
    System.out.println(m.group()); // 100, 200
}

五、常见正则表达式示例

1. 验证类正则

// 电子邮件
String emailRegex = "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";

// 手机号(中国大陆)
String phoneRegex = "^1[3-9]\\d{9}$";

// 身份证号(18位)
String idCardRegex = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$";

// URL验证
String urlRegex = "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$";

2. 提取类正则

// 提取HTML标签内容
Pattern tagPattern = Pattern.compile("<([a-z]+)>(.*?)</\\1>");
Matcher tagMatcher = tagPattern.matcher("<div>content</div>");

// 提取中文
Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fa5]+");

// 提取IP地址
Pattern ipPattern = Pattern.compile("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b");

六、性能优化与陷阱

1. 预编译模式

// 错误做法:每次调用都编译
void process(String text) {
    Pattern.compile(regex).matcher(text).matches(); // 低效
}

// 正确做法:静态预编译
class Validator {
    private static final Pattern EMAIL_PATTERN = 
        Pattern.compile("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$");

    public static boolean isValidEmail(String email) {
        return EMAIL_PATTERN.matcher(email).matches();
    }
}

2. 常见陷阱

// 陷阱1:忘记转义特殊字符
Pattern.compile("1.2").matcher("123").matches(); // true (点匹配任意字符)

// 陷阱2:过度使用.*
Pattern.compile("A.*B").matcher("AxxxBxxxB").matches(); // 可能意外匹配

// 陷阱3:忽略多行模式
String text = "line1\nline2";
Pattern.compile("^line").matcher(text).find(); // 只匹配第一行
Pattern.compile("^line", Pattern.MULTILINE).matcher(text).find(); // 匹配所有行

七、实战案例

1. 日志解析

String logEntry = "2023-05-15 14:30:22 [ERROR] com.example.Service - NullPointerException";
Pattern logPattern = Pattern.compile(
    "(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) \\[(\\w+)\\] ([\\w.]+) - (.+)"
);

Matcher m = logPattern.matcher(logEntry);
if (m.matches()) {
    String date = m.group(1);
    String level = m.group(3);
    String message = m.group(5);
    // 处理日志...
}

2. CSV解析

String csvLine = "John,\"Doe, Jr.\",30,\"New York, NY\"";
Pattern csvPattern = Pattern.compile(
    "\"([^\"]*)\"|([^,]+),?"
);

List<String> fields = new ArrayList<>();
Matcher m = csvPattern.matcher(csvLine);
while (m.find()) {
    fields.add(m.group(1) != null ? m.group(1) : m.group(2));
}
// fields: ["John", "Doe, Jr.", "30", "New York, NY"]

八、进阶特性

1. 命名捕获组

Pattern p = Pattern.compile(
    "(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})"
);
Matcher m = p.matcher("2023-05-15");

if (m.matches()) {
    String year = m.group("year");  // 2023
    String month = m.group("month"); // 05
    String day = m.group("day");     // 15
}

2. 模式标志

标志常量说明
Pattern.CASE_INSENSITIVE忽略大小写
Pattern.MULTILINE多行模式(^和$匹配行首尾)
Pattern.DOTALL点号匹配所有字符包括换行符
Pattern.UNICODE_CASEUnicode感知的大小写忽略
// 组合使用多个标志
Pattern.compile("^[a-z]+$", 
    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
);

九、性能测试与对比

1. 不同实现方式性能

方法10万次调用耗时(ms)
String.matches()1200
预编译Pattern350
重用Matcher280

2. 复杂正则优化建议

  1. 避免回溯爆炸:谨慎使用嵌套量词 (a+)+
  2. 使用原子组(?>...) 防止回溯
  3. 具体化字符类:用 [a-z] 代替 .*?
  4. 合理使用锚点^$ 限制匹配范围

通过掌握这些正则表达式技巧,您可以在Java中高效处理各种文本匹配、验证和提取需求。记住复杂的正则表达式虽然强大,但也可能难以维护,在适当情况下考虑拆分为多个简单正则或结合其他字符串操作方法。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞51 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容