ZetCode

Java Matcher.region 方法

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

Java 的 regex 包中的 Matcher.region 方法允许您将模式匹配限制为输入序列的特定区域。当您只需要在文本的一部分中搜索或匹配时,这很有用。

通过设置区域,您可以通过避免不必要地处理整个输入来提高性能。该区域由开始和结束索引定义,匹配操作将仅考虑此范围内的字符。

Matcher.region 方法概述

region 方法接受两个参数:开始索引(包含)和结束索引(不包含)。它返回 Matcher 本身,允许方法链接。区域设置会影响所有后续的匹配操作。

重要的相关方法包括 regionStartregionEnd,它们返回当前的区域边界,以及 hasTransparentBounds,它检查边界是否透明。

Matcher.region 的基本用法

此示例演示了 region 方法的最简单用法,用于将匹配限制为输入字符串的特定部分。我们将在定义的区域内搜索一个模式。

MatcherRegionBasic.java
package com.zetcode;

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

public class MatcherRegionBasic {

    public static void main(String[] args) {
        
        String input = "The quick brown fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("fox");
        Matcher matcher = pattern.matcher(input);
        
        // Set region from index 10 to 20
        matcher.region(10, 20);
        
        if (matcher.find()) {
            System.out.println("Found '" + matcher.group() + 
                "' at position " + matcher.start());
        } else {
            System.out.println("No match found in region");
        }
        
        System.out.println("Region start: " + matcher.regionStart());
        System.out.println("Region end: " + matcher.regionEnd());
    }
}

在本例中,我们搜索单词 "fox",但仅在输入字符串的索引 10 到 20 的区域内搜索。匹配器将仅考虑文本的这一部分进行匹配操作。

regionStartregionEnd 方法确认当前区域边界。匹配成功,因为 "fox" 位于指定的区域内。

区域超出匹配范围

此示例显示了当我们搜索的模式位于定义区域之外时会发生什么情况。匹配器将不会在指定的区域边界之外找到匹配项。

MatcherRegionOutside.java
package com.zetcode;

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

public class MatcherRegionOutside {

    public static void main(String[] args) {
        
        String input = "Java programming is fun and Java is powerful";
        Pattern pattern = Pattern.compile("Java");
        Matcher matcher = pattern.matcher(input);
        
        // Set region that excludes both "Java" occurrences
        matcher.region(5, 30);
        
        int count = 0;
        while (matcher.find()) {
            count++;
            System.out.println("Match found at " + matcher.start());
        }
        
        System.out.println("Total matches in region: " + count);
    }
}

这里我们搜索 "Java",但设置了一个排除输入字符串中该词的两个出现的区域。匹配器正确地报告了在指定的区域内没有匹配项。

这演示了 region 方法如何有效地限制模式匹配操作的范围,这对于性能优化很有用。

带有区域的锚点

此示例探讨了锚点(^ 和 $)与区域一起使用时的行为。锚点尊重区域边界,而不是完整的输入字符串。

MatcherRegionAnchors.java
package com.zetcode;

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

public class MatcherRegionAnchors {

    public static void main(String[] args) {
        
        String input = "Start middle end";
        Pattern startPattern = Pattern.compile("^Start");
        Pattern middlePattern = Pattern.compile("^middle");
        Pattern endPattern = Pattern.compile("end$");
        
        // Full string matching
        Matcher matcher = startPattern.matcher(input);
        System.out.println("Matches full string start: " + matcher.find());
        
        // Set region to "middle end"
        matcher.region(6, input.length());
        System.out.println("Matches region start: " + 
            middlePattern.matcher(input).region(6, input.length()).find());
            
        // Set region to "middle"
        matcher = endPattern.matcher(input);
        matcher.region(6, 12);
        System.out.println("Matches region end: " + matcher.find());
    }
}

该示例显示,在一个区域内,^ 锚点匹配区域的开始,而不是原始字符串。类似地,$ 匹配区域的结束。

当您使用包含锚点的区域和模式时,理解此行为很重要,因为它会影响模式的匹配方式。

带有 find(int start) 的区域

此示例演示了 region 方法与 find(int start) 之间的交互。find 的开始参数相对于区域,而不是完整的输入。

MatcherRegionFindStart.java
package com.zetcode;

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

public class MatcherRegionFindStart {

    public static void main(String[] args) {
        
        String input = "abc123def456ghi789";
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(input);
        
        // Set region from index 3 to 15 ("123def456")
        matcher.region(3, 15);
        
        // Start searching from position 3 within region
        System.out.println("Matches from position 3:");
        while (matcher.find(3)) {
            System.out.println(matcher.group() + " at " + matcher.start());
        }
        
        // Start searching from position 6 within region
        System.out.println("\nMatches from position 6:");
        matcher.reset();
        while (matcher.find(6)) {
            System.out.println(matcher.group() + " at " + matcher.start());
        }
    }
}

该示例显示 find(int start) 将开始参数视为相对于区域的开始,而不是完整输入字符串的开头。区域边界仍然限制了匹配。

此行为允许精确控制匹配应该在区域内的哪个位置开始,同时仍然遵守总体区域约束。

透明边界

此示例演示了将透明边界与区域一起使用。当边界透明时,lookahead 和 lookbehind 可以看到超出区域边界的范围。

MatcherRegionTransparent.java
package com.zetcode;

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

public class MatcherRegionTransparent {

    public static void main(String[] args) {
        
        String input = "prefix123main456suffix";
        Pattern pattern = Pattern.compile("(?<=prefix)\\d+");
        Matcher matcher = pattern.matcher(input);
        
        // Set region that excludes "prefix"
        matcher.region(6, 15); // "123main"
        
        // Without transparent bounds (default)
        System.out.println("Without transparent bounds:");
        if (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        } else {
            System.out.println("No match");
        }
        
        // With transparent bounds
        matcher.reset();
        matcher.region(6, 15);
        matcher.useTransparentBounds(true);
        System.out.println("\nWith transparent bounds:");
        if (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        } else {
            System.out.println("No match");
        }
    }
}

该示例显示了透明边界如何影响 lookbehind 操作。使用默认的 opaque 边界,lookbehind 失败,因为它无法看到区域之外的内容。使用透明边界,它将成功。

当您需要匹配依赖于您主要感兴趣的区域之外的上下文的模式时,此功能特别有用。

带有 replaceAll 的区域

此示例显示了 region 方法如何影响替换操作。仅替换区域内的匹配项,而外部文本保持不变。

MatcherRegionReplace.java
package com.zetcode;

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

public class MatcherRegionReplace {

    public static void main(String[] args) {
        
        String input = "apple banana apple cherry apple";
        Pattern pattern = Pattern.compile("apple");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to replace only the middle "apple"
        matcher.region(7, 20); // "banana apple cherry"
        
        String result = matcher.replaceAll("orange");
        System.out.println("Original: " + input);
        System.out.println("Modified: " + result);
        
        // Verify region boundaries
        System.out.println("Region start: " + matcher.regionStart());
        System.out.println("Region end: " + matcher.regionEnd());
    }
}

该示例演示了 replaceAll 仅替换指定区域内的匹配项。第一个和最后一个 "apple" 保持不变,因为它们位于区域之外。

当您需要仅修改字符串的特定部分而保留其他部分不变时,此选择性替换功能非常有用。

带有多个模式的区域

此最后一个示例展示了如何将相同的区域设置与多个模式一起使用。在用新模式重置匹配器后,该区域将持续存在。

MatcherRegionMultiple.java
package com.zetcode;

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

public class MatcherRegionMultiple {

    public static void main(String[] args) {
        
        String input = "Name: John, Age: 30, City: New York";
        Matcher matcher = Pattern.compile(":").matcher(input);
        
        // Set region to "Age: 30, City:"
        matcher.region(12, 25);
        
        // Find colons in region
        System.out.println("Colons in region:");
        while (matcher.find()) {
            System.out.println("Found at " + matcher.start());
        }
        
        // Reset with new pattern but keep region
        matcher.usePattern(Pattern.compile("\\d+"));
        System.out.println("\nNumbers in same region:");
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
    }
}

该示例显示,使用 usePattern 更改模式时,区域设置会持续存在。这允许在文本的同一区域内高效地搜索不同的模式。

区域边界在模式更改之间保持一致,为所有匹配操作提供一致的范围。

来源

Java Matcher.region 文档

在本文中,我们通过实际示例深入探讨了 Matcher.region 方法。此强大功能使您能够精确控制 Java 应用程序中的正则表达式匹配边界。

作者

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

列出所有Java教程