Java 正则表达式完全指南

Java通过 java.util.regex 包提供正则表达式支持,主要包含 Pattern 和 Matcher 两个核心类。本指南将详细介绍Java中正则表达式的使用方法和最佳实践。

1. 基础知识

1.1 主要类介绍

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

public class RegexBasics {
    public static void main(String[] args) {
        // Pattern 类:编译正则表达式
        Pattern pattern = Pattern.compile("\\d+");

        // Matcher 类:执行匹配操作
        Matcher matcher = pattern.matcher("123");

        // String 类的正则方法
        "text".matches("\\w+");         // 匹配
        "text".replaceAll("\\w+", "*"); // 替换
        "text".split("\\s+");           // 分割
    }
}

1.2 基本匹配方法

public class RegexMethods {
    public static void main(String[] args) {
        String text = "Hello, my phone is 123-456-7890";
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(text);

        // 1. 查找第一个匹配
        if (matcher.find()) {
            System.out.println("First match: " + matcher.group());
        }

        // 2. 查找所有匹配
        matcher.reset(); // 重置匹配器
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }

        // 3. 完全匹配
        System.out.println("123".matches("\\d+"));  // true
    }
}

2. 正则表达式语法

2.1 字符匹配

public class CharacterMatching {
    public static void main(String[] args) {
        String text = "Java 17 is awesome! Price: $99.99";

        // 匹配数字
        Pattern digits = Pattern.compile("\\d+");
        
        // 匹配单词
        Pattern words = Pattern.compile("\\w+");
        
        // 匹配空白字符
        Pattern spaces = Pattern.compile("\\s+");
        
        // 自定义字符类
        Pattern vowels = Pattern.compile("[aeiou]");
        
        // 使用Matcher查找
        Matcher matcher = digits.matcher(text);
        while (matcher.find()) {
            System.out.println("Number found: " + matcher.group());
        }
    }
}

2.2 量词使用

public class Quantifiers {
    public static void main(String[] args) {
        String text = "Java JavaJava JavaJavaJava";

        // * - 零次或多次
        Pattern p1 = Pattern.compile("Java*");

        // + - 一次或多次
        Pattern p2 = Pattern.compile("Java+");

        // ? - 零次或一次
        Pattern p3 = Pattern.compile("Java?");

        // {n} - 精确n次
        Pattern p4 = Pattern.compile("(Java){2}");

        // {n,m} - n到m次
        Pattern p5 = Pattern.compile("(Java){2,3}");
    }
}

3. 高级特性

3.1 分组和捕获

public class GroupingExample {
    public static void main(String[] args) {
        String text = "John Smith, Jane Doe, Bob Johnson";
        Pattern pattern = Pattern.compile("(\\w+)\\s(\\w+)");
        Matcher matcher = pattern.matcher(text);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("First name: " + matcher.group(1));
            System.out.println("Last name: " + matcher.group(2));
        }

        // 命名捕获组
        Pattern namedPattern = Pattern.compile("(?<first>\\w+)\\s(?<last>\\w+)");
        Matcher namedMatcher = namedPattern.matcher(text);
        
        while (namedMatcher.find()) {
            System.out.println("First name: " + namedMatcher.group("first"));
            System.out.println("Last name: " + namedMatcher.group("last"));
        }
    }
}

3.2 边界匹配

public class BoundaryMatching {
    public static void main(String[] args) {
        String text = "Hello World\nNew Line";

        // ^ - 行的开始
        Pattern startLine = Pattern.compile("^Hello");

        // $ - 行的结束
        Pattern endLine = Pattern.compile("Line$");

        // \b - 单词边界
        Pattern wordBoundary = Pattern.compile("\\bWorld\\b");

        // 多行模式
        Pattern multiLine = Pattern.compile("^\\w+", Pattern.MULTILINE);
    }
}

4. 实用示例

4.1 数据验证器

public class Validator {
    // 编译后的Pattern是线程安全的,可以静态存储
    private static final Pattern EMAIL_PATTERN = 
        Pattern.compile("^[A-Za-z0-9+_.-]+@(.+)$");
    
    private static final Pattern PHONE_PATTERN = 
        Pattern.compile("^1[3-9]\\d{9}$");
    
    private static final Pattern PASSWORD_PATTERN = 
        Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$");

    public static boolean validateEmail(String email) {
        return email != null && EMAIL_PATTERN.matcher(email).matches();
    }

    public static boolean validatePhone(String phone) {
        return phone != null && PHONE_PATTERN.matcher(phone).matches();
    }

    public static boolean validatePassword(String password) {
        return password != null && PASSWORD_PATTERN.matcher(password).matches();
    }
}

4.2 文本处理工具

public class TextProcessor {
    private static final Pattern URL_PATTERN = 
        Pattern.compile("https?://(?:[-\\w.]|(?:%[\\da-fA-F]{2}))+[^\\s]*");
    
    private static final Pattern HTML_TAG_PATTERN = 
        Pattern.compile("<[^>]+>");

    // 提取URL
    public static List<String> extractUrls(String text) {
        List<String> urls = new ArrayList<>();
        Matcher matcher = URL_PATTERN.matcher(text);
        while (matcher.find()) {
            urls.add(matcher.group());
        }
        return urls;
    }

    // 清理HTML标签
    public static String stripHtmlTags(String html) {
        return HTML_TAG_PATTERN.matcher(html).replaceAll("");
    }

    // 清理多余空白
    public static String cleanWhitespace(String text) {
        return text.replaceAll("\\s+", " ").trim();
    }
}

5. 性能优化

5.1 Pattern复用

public class RegexOptimization {
    // 正确方式:复用编译后的Pattern
    private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");

    public static List<String> findNumbers(String text) {
        List<String> numbers = new ArrayList<>();
        Matcher matcher = NUMBER_PATTERN.matcher(text);
        while (matcher.find()) {
            numbers.add(matcher.group());
        }
        return numbers;
    }

    // 错误方式:重复编译Pattern
    public static boolean badExample(String text) {
        return text.matches("\\d+");  // 每次调用都会重新编译
    }
}

5.2 StringBuilder优化

public class StringBuilderExample {
    public static String replaceWithCallback(String input, Pattern pattern, 
            Function<String, String> callback) {
        Matcher matcher = pattern.matcher(input);
        StringBuilder result = new StringBuilder();
        int lastIndex = 0;
        
        while (matcher.find()) {
            result.append(input, lastIndex, matcher.start());
            result.append(callback.apply(matcher.group()));
            lastIndex = matcher.end();
        }
        
        result.append(input, lastIndex, input.length());
        return result.toString();
    }
}

6. 异常处理

public class RegexExceptionHandling {
    public static Pattern compilePattern(String regex) {
        try {
            return Pattern.compile(regex);
        } catch (PatternSyntaxException e) {
            System.err.println("Invalid regex pattern: " + e.getMessage());
            System.err.println("Pattern: " + e.getPattern());
            System.err.println("Index: " + e.getIndex());
            return null;
        }
    }

    public static boolean safeMatch(String text, String regex) {
        try {
            Pattern pattern = Pattern.compile(regex);
            return pattern.matcher(text).matches();
        } catch (PatternSyntaxException e) {
            System.err.println("Regex syntax error: " + e.getMessage());
            return false;
        } catch (Exception e) {
            System.err.println("Unexpected error: " + e.getMessage());
            return false;
        }
    }
}

7. 单元测试

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class ValidatorTest {
    @Test
    public void testEmailValidation() {
        assertTrue(Validator.validateEmail("test@example.com"));
        assertTrue(Validator.validateEmail("user@domain.co.uk"));
        assertFalse(Validator.validateEmail("invalid.email"));
        assertFalse(Validator.validateEmail("@domain.com"));
    }

    @Test
    public void testPhoneValidation() {
        assertTrue(Validator.validatePhone("13812345678"));
        assertFalse(Validator.validatePhone("12345678"));
        assertFalse(Validator.validatePhone("2381234567"));
    }

    @Test
    public void testPasswordValidation() {
        assertTrue(Validator.validatePassword("Pass1word@"));
        assertFalse(Validator.validatePassword("password"));
        assertFalse(Validator.validatePassword("12345678"));
    }
}

8. 常见问题和解决方案

8.1 特殊字符处理

public class SpecialCharacterHandling {
    public static String escapeSpecialCharacters(String literal) {
        return Pattern.quote(literal);
    }

    public static String createRegexFromLiteral(String literal) {
        StringBuilder regex = new StringBuilder();
        for (char c : literal.toCharArray()) {
            if ("[](){}.*+?^$\\|".indexOf(c) != -1) {
                regex.append('\\');
            }
            regex.append(c);
        }
        return regex.toString();
    }
}

8.2 Unicode支持

public class UnicodeSupport {
    public static void main(String[] args) {
        // 使用UNICODE_CHARACTER_CLASS标志
        Pattern pattern = Pattern.compile("\\p{L}+", 
            Pattern.UNICODE_CHARACTER_CLASS);
        
        String text = "Hello 你好 こんにちは";
        Matcher matcher = pattern.matcher(text);
        
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
    }
}

总结

Java的正则表达式实现具有以下特点:

  1. 强大的Pattern和Matcher类
  2. 完整的Unicode支持
  3. 线程安全的Pattern对象
  4. 丰富的API支持

最佳实践:

  1. 复用编译后的Pattern对象
  2. 使用命名捕获组提高可读性
  3. 正确处理特殊字符
  4. 注意性能优化
  5. 做好异常处理
  6. 编写单元测试

注意事项:

  1. Pattern编译开销较大,应该重用
  2. 避免在循环中创建Pattern对象
  3. 使用StringBuilder优化字符串操作
  4. 考虑Unicode支持需求

记住:在Java中使用正则表达式时,应该平衡效率和可维护性。合理使用Pattern的复用机制,可以显著提高性能。同时,通过良好的代码组织和命名约定,保持代码的可维护性。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐