ZetCode

Java Matcher.useTransparentBounds 方法

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

Matcher.useTransparentBounds 方法控制匹配器是否考虑区域边界之外的文本,用于先行和后行操作。 启用后,这些操作可以“看到”匹配区域之外的内容。

透明边界会影响环视断言在区域边界的行为。 默认情况下,透明边界是禁用的,这意味着环视只能看到当前匹配区域内的文本。此方法是 Java 的正则表达式包的一部分。

Matcher 类概述

Matcher 类解释模式并对输入字符串执行匹配操作。它提供了查询匹配结果和修改匹配行为的方法。Matcher 对象是从 Pattern 对象创建的。

关键方法包括 matches, findgroupregion 方法定义匹配的边界,而 useTransparentBounds 影响在这些边界处的环视行为。

基本 useTransparentBounds 示例

此示例演示了 useTransparentBounds 的基本用法。我们将比较启用和禁用透明边界时的匹配行为。

TransparentBoundsBasic.java
package com.zetcode;

import java.util.regex.*;

public class TransparentBoundsBasic {
    public static void main(String[] args) {
        String input = "apple banana cherry";
        Pattern pattern = Pattern.compile("(?<=banana )\\w+");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to exclude "banana "
        matcher.region(7, input.length());
        
        // Without transparent bounds (default)
        System.out.println("Without transparent bounds:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
        
        // With transparent bounds
        matcher.reset();
        matcher.useTransparentBounds(true);
        System.out.println("\nWith transparent bounds:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
    }
}

在这个例子中,我们创建一个模式,在匹配单词之前向后查找 "banana "。 在禁用透明边界(默认)的情况下,后向查找失败,因为 "banana " 在区域之外。 启用后,后向查找可以查看区域边界之外的内容并成功。

带先行断言的透明边界

此示例显示了透明边界如何影响区域末尾的先行断言。我们将匹配一个单词,后面跟着区域之外的特定文本。

TransparentBoundsLookahead.java
package com.zetcode;

import java.util.regex.*;

public class TransparentBoundsLookahead {
    public static void main(String[] args) {
        String input = "red green blue yellow";
        Pattern pattern = Pattern.compile("\\w+(?= yellow)");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to exclude " yellow"
        matcher.region(0, input.length() - 7);
        
        // Without transparent bounds
        System.out.println("Without transparent bounds:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
        
        // With transparent bounds
        matcher.reset();
        matcher.useTransparentBounds(true);
        System.out.println("\nWith transparent bounds:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
    }
}

在这里,我们尝试匹配一个单词,后面跟着 " yellow"。 在禁用透明边界的情况下,先行查找失败,因为 " yellow" 在区域之外。 启用后,先行查找可以查看区域边界之外的内容并匹配 "blue"。

与锚定边界相结合

此示例演示了透明边界如何与锚定边界交互。 锚定边界影响 ^ 和 $ 的行为,而透明边界影响环视。

TransparentAnchoringBounds.java
package com.zetcode;

import java.util.regex.*;

public class TransparentAnchoringBounds {
    public static void main(String[] args) {
        String input = "start middle end";
        Pattern pattern = Pattern.compile("(?<=start )\\w+");
        Matcher matcher = pattern.matcher(input);
        
        // Set region to "middle end"
        matcher.region(6, input.length());
        
        // Default (no transparent bounds, anchoring bounds true)
        System.out.println("Default settings:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
        
        // Transparent bounds true, anchoring bounds true
        matcher.reset();
        matcher.useTransparentBounds(true);
        System.out.println("\nTransparent true, anchoring true:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
        
        // Transparent bounds true, anchoring bounds false
        matcher.reset();
        matcher.useAnchoringBounds(false);
        System.out.println("\nTransparent true, anchoring false:");
        while (matcher.find()) {
            System.out.println("Match: " + matcher.group());
        }
    }
}

此示例显示了三种配置。 使用默认设置,后向查找失败。 启用透明边界后,它会成功。 锚定边界不会影响环视,但在区域边界处控制 ^ 和 $ 的行为。

实际用例:部分匹配

此示例演示了透明边界如何帮助识别较大文本中的部分匹配的实际用例,这在文本编辑器或 IDE 中很有用。

PartialMatching.java
package com.zetcode;

import java.util.regex.*;

public class PartialMatching {
    public static void main(String[] args) {
        String document = "The quick brown fox jumps over the lazy dog.";
        String searchTerm = "fox jumps";
        
        // Simulate user selecting "brown fox jumps over"
        int selectionStart = 10;
        int selectionEnd = 28;
        
        Pattern pattern = Pattern.compile("(?<=\\b)\\w+");
        Matcher matcher = pattern.matcher(document);
        matcher.region(selectionStart, selectionEnd);
        
        // Without transparent bounds
        System.out.println("Words starting in selection (default):");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
        
        // With transparent bounds to include word boundaries
        matcher.reset();
        matcher.useTransparentBounds(true);
        System.out.println("\nWords starting in selection (transparent):");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

在这种情况下,我们希望找到在选定区域内开始的单词。 在禁用透明边界的情况下,我们会错过在选择之前开始的单词。 启用后,单词边界断言可以查看区域之外的内容。

性能注意事项

此示例比较了使用透明边界的性能影响,表明它们在某些情况下会影响匹配速度。

PerformanceComparison.java
package com.zetcode;

import java.util.regex.*;
import java.util.concurrent.TimeUnit;

public class PerformanceComparison {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100000; i++) {
            sb.append("abc ");
        }
        String input = sb.toString();
        Pattern pattern = Pattern.compile("(?<=abc )\\w+");
        
        long start, end;
        
        // Without transparent bounds
        Matcher matcher = pattern.matcher(input);
        matcher.region(4, input.length());
        start = System.nanoTime();
        while (matcher.find()) {}
        end = System.nanoTime();
        System.out.printf("Without transparent: %d ms%n", 
            TimeUnit.NANOSECONDS.toMillis(end - start));
        
        // With transparent bounds
        matcher.reset();
        matcher.useTransparentBounds(true);
        start = System.nanoTime();
        while (matcher.find()) {}
        end = System.nanoTime();
        System.out.printf("With transparent: %d ms%n", 
            TimeUnit.NANOSECONDS.toMillis(end - start));
    }
}

此基准测试表明,透明边界可能会增加匹配操作的开销,尤其是在有许多环视断言的情况下。 这种差异在使用大型输入字符串或复杂模式时变得更加明显。

特殊情况:零长度区域

此示例探讨了透明边界在零长度区域中的行为,这是一种可能发生在某些文本处理场景中的特殊情况。

ZeroLengthRegion.java
package com.zetcode;

import java.util.regex.*;

public class ZeroLengthRegion {
    public static void main(String[] args) {
        String input = "prefix123suffix";
        Pattern pattern = Pattern.compile("(?<=prefix)\\d+");
        Matcher matcher = pattern.matcher(input);
        
        // Set zero-length region at position 6
        matcher.region(6, 6);
        
        // Without transparent bounds
        System.out.println("Zero-length region (default):");
        System.out.println("Matches: " + matcher.find());
        
        // With transparent bounds
        matcher.reset();
        matcher.useTransparentBounds(true);
        System.out.println("\nZero-length region (transparent):");
        System.out.println("Matches: " + matcher.find());
    }
}

对于零长度区域,匹配行为变得有趣。 没有透明边界,就不会发生匹配。 启用它们后,环视仍然可以检查零长度区域之外的文本,从而可能找到匹配项。

来源

Java Matcher.useTransparentBounds 文档

在本文中,我们深入探讨了 Matcher.useTransparentBounds 方法。 理解此功能对于涉及区域和环视断言的高级正则表达式匹配场景至关重要。

作者

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

列出所有Java教程