ZetCode

Java Matcher.useAnchoringBounds 方法

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

Matcher.useAnchoringBounds 方法控制匹配器在执行正则表达式操作时是否使用定位边界。定位边界影响 ^ 和 $ 定位符相对于输入区域的行为。

启用定位边界(默认)时,^ 匹配输入区域的开头,$ 匹配结尾。禁用时,这些定位符仅匹配整个输入字符串的实际开头/结尾。

基本定义

Matcher:一个 Java 类,通过解释 Pattern 对字符序列执行匹配操作。它提供了查找、匹配和替换文本的方法。

定位边界:一个设置,用于确定 ^ 和 $ 是匹配输入区域的边界(true)还是仅匹配输入的绝对开头/结尾(false)。

输入区域:当前正在考虑用于匹配的输入字符串的部分,可以使用 region 方法设置。

默认定位边界行为

此示例演示了启用定位边界时的默认行为。 ^ 和 $ 定位符匹配输入区域的开头和结尾。

AnchoringBoundsDefault.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsDefault {

    public static void main(String[] args) {
        String input = "start middle end";
        Pattern pattern = Pattern.compile("^middle$");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to "middle"
        matcher.region(6, 12);
        
        // Default anchoring bounds is true
        System.out.println("Default anchoring bounds: " + matcher.useAnchoringBounds(true));
        System.out.println("Matches in region: " + matcher.find());
    }
}

在此示例中,我们将区域设置为“middle”,并尝试匹配“^middle$”。使用默认的定位边界(true),匹配成功,因为 ^ 和 $ 匹配区域边界。输出显示默认设置和匹配都为 true。

禁用定位边界

此示例显示了禁用定位边界时会发生什么。 ^ 和 $ 定位符将仅匹配输入字符串的绝对开头/结尾。

AnchoringBoundsDisabled.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsDisabled {

    public static void main(String[] args) {
        String input = "start middle end";
        Pattern pattern = Pattern.compile("^middle$");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to "middle"
        matcher.region(6, 12);
        
        // Disable anchoring bounds
        matcher.useAnchoringBounds(false);
        System.out.println("Anchoring bounds disabled: " + !matcher.useAnchoringBounds());
        System.out.println("Matches in region: " + matcher.find());
    }
}

禁用定位边界后,相同的模式“^middle$”无法匹配,因为 ^ 和 $ 不再遵循区域边界。输出显示匹配尝试失败,演示了不同的行为。

具有多个区域的定位边界

此示例演示了定位边界如何影响同一输入字符串的多个区域的匹配。

AnchoringBoundsMultiRegion.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsMultiRegion {

    public static void main(String[] args) {
        String input = "first second third";
        Pattern pattern = Pattern.compile("^\\w+$");
        Matcher matcher = pattern.matcher(input);
        
        // Test with anchoring bounds enabled (default)
        System.out.println("With anchoring bounds:");
        testRegions(matcher, true);
        
        // Test with anchoring bounds disabled
        System.out.println("\nWithout anchoring bounds:");
        testRegions(matcher, false);
    }
    
    private static void testRegions(Matcher matcher, boolean enable) {
        matcher.useAnchoringBounds(enable);
        
        // Test three different regions
        matcher.region(0, 5);   // "first"
        System.out.println("Region 1 match: " + matcher.find());
        
        matcher.region(6, 12);  // "second"
        System.out.println("Region 2 match: " + matcher.find());
        
        matcher.region(13, 18); // "third"
        System.out.println("Region 3 match: " + matcher.find());
    }
}

此示例针对输入字符串的三个不同区域测试模式“^\w+$”。启用定位边界后,所有区域都匹配,因为 ^ 和 $ 匹配区域边界。禁用定位边界后,不会发生匹配,因为该模式需要匹配输入的绝对开头/结尾。

与透明边界结合

此示例显示了定位边界如何与透明边界交互,透明边界会影响后行断言和先行断言。

AnchoringBoundsWithTransparent.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsWithTransparent {

    public static void main(String[] args) {
        String input = "prefix123suffix";
        Pattern pattern = Pattern.compile("(?<=prefix)\\d+(?=suffix)");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to "123suffix"
        matcher.region(6, 15);
        
        // Case 1: Both bounds enabled
        matcher.useAnchoringBounds(true);
        matcher.useTransparentBounds(false);
        System.out.println("Anchoring true, Transparent false: " + matcher.find());
        
        // Case 2: Anchoring disabled, Transparent false
        matcher.useAnchoringBounds(false);
        matcher.useTransparentBounds(false);
        System.out.println("Anchoring false, Transparent false: " + matcher.find());
        
        // Case 3: Anchoring false, Transparent true
        matcher.useAnchoringBounds(false);
        matcher.useTransparentBounds(true);
        System.out.println("Anchoring false, Transparent true: " + matcher.find());
    }
}

此示例演示了定位边界和透明边界之间的交互。当透明边界为 false 时,后行断言 (?<=prefix) 失败,因为它无法看到区域外部。只有第三种情况成功,因为透明边界允许环视断言看到区域外部。

实际用例

此示例显示了一个实际用例,用于在搜索较大文本中的模式时禁用定位边界。

AnchoringBoundsPractical.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsPractical {

    public static void main(String[] args) {
        String text = "Error: Invalid input\nWarning: Low memory\nError: File not found";
        Pattern errorPattern = Pattern.compile("^Error: .+$", Pattern.MULTILINE);
        Matcher matcher = errorPattern.matcher(text);
        
        // With default anchoring bounds (matches only first line)
        System.out.println("With default anchoring bounds:");
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
        
        // With anchoring bounds disabled (matches all error lines)
        matcher.useAnchoringBounds(false);
        System.out.println("\nWith anchoring bounds disabled:");
        matcher.reset();
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
    }
}

在这个实际示例中,我们搜索日志中的错误消息。使用默认定位边界,只有第一行匹配,因为 ^ 和 $ 匹配区域边界。禁用定位边界允许在与 MULTILINE 模式结合使用时匹配所有错误行。

性能影响

此示例演示了在处理具有许多区域的大型文本时,定位边界的潜在性能影响。

AnchoringBoundsPerformance.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsPerformance {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append("word").append(i).append(" ");
        }
        String input = sb.toString();
        Pattern pattern = Pattern.compile("^word\\d+$");
        Matcher matcher = pattern.matcher(input);
        
        // Test with anchoring bounds enabled
        long start = System.nanoTime();
        testWithAnchoring(matcher, true);
        long duration1 = System.nanoTime() - start;
        
        // Test with anchoring bounds disabled
        start = System.nanoTime();
        testWithAnchoring(matcher, false);
        long duration2 = System.nanoTime() - start;
        
        System.out.printf("With anchoring bounds: %,d ns%n", duration1);
        System.out.printf("Without anchoring bounds: %,d ns%n", duration2);
    }
    
    private static void testWithAnchoring(Matcher matcher, boolean enable) {
        matcher.useAnchoringBounds(enable);
        matcher.reset();
        
        int pos = 0;
        while (pos < matcher.regionEnd()) {
            int spacePos = matcher.regionEnd();
            if (matcher.regionEnd() > pos) {
                spacePos = matcher.regionEnd();
                for (int i = pos; i < matcher.regionEnd(); i++) {
                    if (matcher.regionEnd() > i &&  
                        matcher.input().charAt(i) == ' ') {
                        spacePos = i;
                        break;
                    }
                }
            }
            matcher.region(pos, spacePos);
            matcher.find();
            pos = spacePos + 1;
        }
    }
}

此性能测试表明,在使用许多小区域时,禁用定位边界有时可以提高性能。 确切的差异取决于正则表达式的复杂性和输入大小,但对于性能至关重要的代码来说,值得考虑。

边缘情况行为

此示例探讨了定位边界行为可能出乎意料或特别重要的边缘情况。

AnchoringBoundsEdgeCases.java
package com.zetcode;

import java.util.regex.*;

public class AnchoringBoundsEdgeCases {

    public static void main(String[] args) {
        // Empty input with empty region
        testCase("", 0, 0);
        
        // Empty region in non-empty input
        testCase("hello", 2, 2);
        
        // Region at exact start
        testCase("start end", 0, 5);
        
        // Region at exact end
        testCase("start end", 6, 9);
    }
    
    private static void testCase(String input, int regionStart, int regionEnd) {
        Pattern pattern = Pattern.compile("^.*$");
        Matcher matcher = pattern.matcher(input);
        matcher.region(regionStart, regionEnd);
        
        System.out.printf("\nInput: '%s', Region: [%d,%d)%n", 
            input, regionStart, regionEnd);
            
        // With anchoring bounds
        matcher.useAnchoringBounds(true);
        System.out.println("Anchoring true: " + matcher.find());
        
        // Without anchoring bounds
        matcher.useAnchoringBounds(false);
        System.out.println("Anchoring false: " + matcher.find());
    }
}

此示例测试空输入和区域等边缘情况。结果表明,定位边界会影响空区域是否匹配“.*”等模式。理解这些边缘情况对于健壮的正则表达式处理非常重要。

来源

Java Matcher.useAnchoringBounds 文档

在本文中,我们深入探讨了 Matcher.useAnchoringBounds 方法。 了解定位边界对于精确控制正则表达式匹配行为至关重要,尤其是在处理输入区域时。

作者

我叫 Jan Bodnar,是一位经验丰富的专业程序员。 我从 2007 年开始撰写编程文章,至今已创作了 1400 多篇文章和 8 本电子书。 凭借八年以上的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程