ZetCode

Java Pattern.compile 方法

上次修改时间:2025 年 4 月 20 日

Pattern.compile 方法是 Java 中创建 Pattern 对象的主要方式。它将给定的正则表达式编译成一个模式,可用于匹配操作。编译后的模式是不可变的并且是线程安全的。

Pattern.compile 有两个主要变体:一个只接受正则表达式字符串,另一个接受正则表达式标志。这些标志修改模式匹配的行为。该方法对无效的正则表达式抛出 PatternSyntaxException 异常。

基本模式编译

Pattern.compile 最简单的形式接受单个正则表达式字符串参数。这将创建一个具有默认匹配行为的 Pattern 对象。然后,编译后的模式可以用于创建 Matcher 对象或执行直接匹配。

BasicCompile.java
package com.zetcode;

import java.util.regex.Pattern;

public class BasicCompile {

    public static void main(String[] args) {
        
        // Simple regex to match words starting with 'J'
        String regex = "\\bJ\\w+\\b";
        String input = "Java JavaScript Python Ruby";
        
        // Compile the pattern
        Pattern pattern = Pattern.compile(regex);
        
        // Use the pattern to find matches
        boolean hasMatch = pattern.matcher(input).find();
        System.out.println("Found match: " + hasMatch);
        
        // Count matches
        long matchCount = pattern.matcher(input).results().count();
        System.out.println("Match count: " + matchCount);
    }
}

此示例演示了基本模式编译和用法。正则表达式匹配以 'J' 开头的单词。我们编译它一次,并在查找和计数匹配项时重复使用它。Pattern 对象是线程安全的,并且可以有效地重复使用。

使用标志编译

Pattern.compile 可以接受修改匹配行为的标志。常见的标志包括 CASE_INSENSITIVEMULTILINEDOTALL。标志作为第二个参数指定,使用按位或运算符来组合多个标志。

CompileWithFlags.java
package com.zetcode;

import java.util.regex.Pattern;

public class CompileWithFlags {

    public static void main(String[] args) {
        
        String regex = "^[a-z]+$";  // Only lowercase letters
        String input = "HELLO\nworld\nJAVA";
        
        // Case insensitive matching
        Pattern caseInsensitive = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        
        // Multiline mode (^ and $ match start/end of lines)
        Pattern multiline = Pattern.compile(regex, 
            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
            
        System.out.println("Case insensitive matches:");
        caseInsensitive.matcher(input).results()
            .forEach(mr -> System.out.println(mr.group()));
            
        System.out.println("\nMultiline matches:");    
        multiline.matcher(input).results()
            .forEach(mr -> System.out.println(mr.group()));
    }
}

此示例演示了标志的用法。第一个模式不区分大小写地匹配,但只找到一个匹配项。第二个模式添加了 MULTILINE 标志,使 ^ 和 $ 在行边界处匹配。这会找到符合条件的每行匹配项。

模式拆分

编译后的模式可以使用 split 方法拆分字符串。这比 String.split 更强大,因为它允许重用编译后的模式。该方法接受一个输入字符串和可选的 limit 参数。

PatternSplitExample.java
package com.zetcode;

import java.util.regex.Pattern;

public class PatternSplitExample {

    public static void main(String[] args) {
        
        // Complex delimiter: comma with optional whitespace
        String regex = "\\s*,\\s*";
        String input = "apple,  orange,banana,,grape";
        
        Pattern pattern = Pattern.compile(regex);
        
        // Split without limit
        String[] fruits = pattern.split(input);
        System.out.println("All fruits:");
        for (String fruit : fruits) {
            System.out.println("'" + fruit + "'");
        }
        
        // Split with limit (max 3 parts)
        String[] limited = pattern.split(input, 3);
        System.out.println("\nLimited split:");
        for (String fruit : limited) {
            System.out.println("'" + fruit + "'");
        }
    }
}

此示例演示了模式拆分。正则表达式处理带可选空格的逗号。第一个拆分处理整个字符串。第二个拆分将结果限制为 3 部分,其余部分不拆分。包含空元素。

使用分组进行模式匹配

编译后的模式可以使用括号捕获分组。分组允许提取匹配项的特定部分。组 0 是整个匹配项,而组 1+ 是捕获的子组。

PatternGroups.java
package com.zetcode;

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

public class PatternGroups {

    public static void main(String[] args) {
        
        // Pattern with capturing groups
        String regex = "(\\d{2})-(\\d{2})-(\\d{4})";
        String input = "Date: 12-31-2023, Another: 01-15-2024";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Month: " + matcher.group(1));
            System.out.println("Day: " + matcher.group(2));
            System.out.println("Year: " + matcher.group(3));
            System.out.println();
        }
    }
}

此示例使用分组提取日期组件。该模式将月、日和年捕获为单独的组。Matcher 的 group 方法检索每个捕获的组。组按其左括号从左到右编号。

命名捕获组

Java 7+ 支持命名捕获组,以获得更具可读性的代码。组使用 (?<name>regex) 语法命名。可以使用名称而不是数字来检索匹配的内容。

NamedGroupsExample.java
package com.zetcode;

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

public class NamedGroupsExample {

    public static void main(String[] args) {
        
        // Pattern with named groups
        String regex = "(?<area>\\d{3})-(?<exchange>\\d{3})-(?<line>\\d{4})";
        String input = "Phone: 123-456-7890, Fax: 987-654-3210";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        while (matcher.find()) {
            System.out.println("Full number: " + matcher.group(0));
            System.out.println("Area code: " + matcher.group("area"));
            System.out.println("Exchange: " + matcher.group("exchange"));
            System.out.println("Line number: " + matcher.group("line"));
            System.out.println();
        }
    }
}

此示例使用命名组来解析电话号码。号码的每个部分都有一个描述性名称。group 方法接受数字或名称。命名组使模式更易于维护,代码更具可读性。

Pattern Quote 方法

Pattern.quote 方法返回一个字面模式字符串。这将转义输入中所有特殊的正则表达式字符。当匹配可能包含正则表达式元字符的字面字符串时,它非常有用。

PatternQuoteExample.java
package com.zetcode;

import java.util.regex.Pattern;

public class PatternQuoteExample {

    public static void main(String[] args) {
        
        String searchString = "file.(txt)";
        String input = "Looking for file.(txt) in directory";
        
        // Without quoting - fails because parentheses are special
        try {
            Pattern badPattern = Pattern.compile(searchString);
            System.out.println("Unquoted match: " + 
                badPattern.matcher(input).find());
        } catch (Exception e) {
            System.out.println("Unquoted pattern failed: " + e.getMessage());
        }
        
        // With quoting - works correctly
        String quoted = Pattern.quote(searchString);
        Pattern goodPattern = Pattern.compile(quoted);
        System.out.println("Quoted match: " + 
            goodPattern.matcher(input).find());
    }
}

此示例显示了引用的重要性。第一次尝试失败,因为括号是正则表达式元字符。引用的版本转义了所有特殊字符,允许精确的字面匹配。始终对用户输入使用引用。

Pattern 谓词

Java 11 向 Pattern 添加了 asPredicateasMatchPredicate 方法。这些将模式转换为用于函数式编程的 Predicate。asPredicate 的行为类似于 find,而 asMatchPredicate 的行为类似于 matches

PatternPredicateExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.stream.Stream;

public class PatternPredicateExample {

    public static void main(String[] args) {
        
        // Email validation pattern
        String regex = "^[\\w.-]+@[\\w.-]+\\.[a-z]{2,}$";
        Pattern emailPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        
        Stream.of("user@example.com", "invalid.email", "admin@test.org")
            .filter(emailPattern.asPredicate())
            .forEach(System.out::println);
            
        System.out.println("\nWith asMatchPredicate:");
        Stream.of("user@example.com", "prefix user@example.com suffix")
            .filter(emailPattern.asMatchPredicate())
            .forEach(System.out::println);
    }
}

此示例演示了模式谓词的实际应用。asPredicate 过滤包含电子邮件地址的字符串。asMatchPredicate 更严格,要求整个字符串是一个电子邮件。两者都对流操作和过滤很有用。

来源

Java Pattern 类文档

本教程涵盖了 Java 中 Pattern.compile 的基本方面。从基本编译到高级功能,如命名组和谓词,这些示例演示了该方法在正则表达式处理中的多功能性。

作者

我的名字是 Jan Bodnar,我是一位经验丰富的程序员,在该领域拥有多年的经验。我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程