对多个区域使用 Matcher.appendReplacement()

2024-03-05

java Matcher.appendReplacement() 方法(带有appendTail())应该让我将源文本转换为结果文本,同时替换所有出现的模式。 伪语言的算法类似于:

while Matcher.find() {
  call Matcher.appendReplacement()
}
call Matcher.appendTail()

如果仅在给定区域内搜索模式,则一切都很好:

call Matcher.region()
while Matcher.find() {
  call Matcher.appendReplacement()
}
call Matcher.appendTail()

当在区域内匹配后,我想进一步移动该区域时,就会出现问题:

call Matcher.region()
while Matcher.find() {
  call Matcher.appendReplacement()
}
call Matcher.region()
while Matcher.find() {
  call Matcher.appendReplacement()
}
call Matcher.appendTail()

这不起作用,因为region()会重置匹配器,以便Matcher.appendReplacement()从文本的开头重新启动,导致结果包含源某些部分的重复。

正如 javadoc 所说,这是设计造成的。

替换可以位于多个区域内的模式的正确方法是什么?

编辑:添加了 java 示例,删除了文本示例

下面的 java 示例显示了来自类似的输入

狗1开始狗2a狗2b结束狗3开始狗4a狗4b结束狗5

你没有得到预期的输出

dog1开始cat2acat2b结束dog3开始cat4acat4b结束dog5

package test;

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

public class TestMatcher {

    public static void main(String[] args) throws Exception {
        String inputText = "dog1 start dog2a dog2b end dog3 start dog4a dog4b end dog5";
        System.out.println("input  = " + inputText);
        StringBuffer result = new StringBuffer();
        Pattern pattern = Pattern.compile("dog");
        Matcher matcher = pattern.matcher(inputText);

        int startPos = inputText.indexOf("start");
        int endPos = inputText.indexOf("end");
        System.out.println("Setting region to " + startPos + "," + endPos);
        matcher.region(startPos, endPos);
        while (matcher.find()) {
            matcher.appendReplacement(result, "cat");
        }
        System.out.println("Partial result = " + result);

        startPos = inputText.indexOf("start", endPos);
        endPos = inputText.indexOf("end", startPos);
        System.out.println("Setting region to " + startPos + "," + endPos);
        matcher.region(startPos, endPos);
        while (matcher.find()) {
            matcher.appendReplacement(result, "cat");
        }
        matcher.appendTail(result);
        System.out.println("Final result   = " + result);
    }
}

Output:

input  = dog1 start dog2a dog2b end dog3 start dog4a dog4b end dog5
Setting region to 5,23
Partial result = dog1 start cat2a cat
Setting region to 32,50
Final result   = dog1 start cat2a catdog1 start dog2a dog2b end dog3 start cat4a cat4b end dog5

子区域不是必须由单独的匹配器处理吗?喜欢:

public static void main(String[] args) {
  String inputText = "dog1 start dog2a dog2b end dog3 start dog4a dog4b end dog5";

  System.out.println("Input          = " + inputText);
  StringBuffer result = new StringBuffer();
  Pattern pattern = Pattern.compile("(start(.*?)end)");

  Matcher matcher = pattern.matcher(inputText);

  while (matcher.find()) {
    int s = matcher.start();
    int e = matcher.end();
    System.out.printf("(%d .. %d) -> \"%s\"\n", s, e, matcher.group(1));
    matcher.appendReplacement(result, processSubGroup(matcher.group(1), matcher.group(2)));
  }
  matcher.appendTail(result);
  System.out.println("Final result   = " + result);
}

static String processSubGroup(String subGroup, String contents) {
  StringBuffer result = new StringBuffer();
  Pattern pattern = Pattern.compile("dog");

  Matcher matcher = pattern.matcher(subGroup);

  while (matcher.find())
    matcher.appendReplacement(result, "cat");

  matcher.appendTail(result);
  return result.toString();
}

或者,没有日志相关的东西并且更简单:

public static void main(String[] args) {
  String inputText = "dog1 start dog2a dog2b end dog3 start dog4a dog4b end dog5";

  StringBuffer result = new StringBuffer();
  Pattern pattern = Pattern.compile("(start(.*?)end)");

  Matcher matcher = pattern.matcher(inputText);

  while (matcher.find())
    matcher.appendReplacement(result, processSubGroup(matcher.group(1), matcher.group(2)));

  matcher.appendTail(result);
  System.out.println("Final result   = " + result);
}

static String processSubGroup(String subGroup, String contents) {
  return Pattern.compile("dog").matcher(subGroup).replaceAll("cat");
}

Result:

Input          = dog1 start dog2a dog2b end dog3 start dog4a dog4b end dog5
(5 .. 26) -> "start dog2a dog2b end"
(32 .. 53) -> "start dog4a dog4b end"
Final result   = dog1 start cat2a cat2b end dog3 start cat4a cat4b end dog5

或者更抽象的方法:

interface GroupProcessor {
  String process(String group);
}

public static void main(String[] args) {
  String inputText = "dog1 dogs dog2a dog2b enddogs cow1 dog3 cows cow2a cow2b endcows dog4 dogs dog5a dog5b enddogs cow3";

  String result = inputText;

  result = processGroup(result, "dogs*enddogs", (group) -> {
    return Pattern.compile("dog").matcher(group).replaceAll("cat");
  });

  result = processGroup(result, "cows*endcows", (group) -> {
    return Pattern.compile("cow").matcher(group).replaceAll("sheep");
  });

  System.out.println("Input        = " + inputText);
  System.out.println("Final result = " + result);
}

static String processGroup(String input, String regex, GroupProcessor processor) {
  StringBuffer result = new StringBuffer();
  Pattern pattern = Pattern.compile(String.format("(%s)", regex.replace("*", "(.*?)")));

  Matcher matcher = pattern.matcher(input);

  while (matcher.find())
    matcher.appendReplacement(result, processor.process(matcher.group(1)));

  matcher.appendTail(result);
  return result.toString();
}

这将为我们提供:

Input        = dog1 dogs dog2a dog2b enddogs cow1 dog3 cows cow2a cow2b endcows dog4 dogs dog5a dog5b enddogs cow3
Final result = dog1 cats cat2a cat2b endcats cow1 dog3 sheeps sheep2a sheep2b endsheeps dog4 cats cat5a cat5b endcats cow3

Upd.

原因,为什么Matcher.region()重置隐式匹配器状态,因此,lastAppendPosition.

appendReplacement and appendTail在某种程度上是一种只向前移动的机制,而.region()并不是那么确定。

假设以下情况:对于 100 个字符的字符串,您应用了区域 0..20,执行find()-appendReplacement()循环,然后将区域移动到例如 30..60,并再次执行替换循环。

现在你有 0..100 源字符串和 0..60 替换结果字符串StringBuffer.

接下来,将区域 10..40 应用到源字符串...接下来做什么?如果源字符串的该区域不包含匹配项 - 好的,什么都不做,但如果它does包含匹配项?应该在哪里appendReplacement追加/插入替换结果?结果字符串已经超过了 10..40 区域并且appendReplacement only appends, not replaces输出缓冲区中字符串的分区。

如果存在某种约束机制,则该区域设置仅限于类似MAX(start, lastAppendPosition)..MIN(end, sourceLength),那么好吧,附加机制可以正常工作,但是.region()方法没有这样的限制,或者它们(限制)会使.region()方法对于搜索来说毫无用处(其中is主要目的.region()方法)。

这就是为什么.region()重置匹配器的隐式状态,使其与appendReplacement()相关的东西。如果您需要不同的行为 - 扩展Matcher通过封装的类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对多个区域使用 Matcher.appendReplacement() 的相关文章

随机推荐

  • 基于 R 中字符串比较的相似度分数(编辑距离)

    我正在尝试根据两个字符串之间的比较来分配相似度分数 R 中是否有相同的函数 我知道 SAS 中有一个名为 SPEDIS 的函数 如果R中有这样的函数 请告诉我 功能adist http stat ethz ch R manual R pat
  • 将 Data.Constraint.Forall 与等式约束一起使用

    假设我有一个这样的函数 LANGUAGE ScopedTypeVariables class C a where foo forall f a b C f a C f b gt f a gt f b foo 现在 如果我想移动范围a and
  • 用于 Web 服务的 SOAP 还是 REST? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 REST 是一种更好的 Web 服务方法还是 SOAP 或者它们是针对不同问题的不同工具吗 或者这是一个微妙的问题 也就是说 一个在某些领域比另
  • Appfabric WF4-WCF服务,如何在没有httpcontext的情况下检索codeactivity中的当前url?

    我开发了一个带有代码活动的 wf wcf 服务 我想在其中检索该服务的当前 URL 如果我禁用 appfabric 的持久性功能 我可以使用以下命令检索 URL HttpContext Current Request Url ToStrin
  • Swift - 协议作为按钮操作的目标类型

    我正在尝试创建 HeaderView 它是 UIView 的子类 它包含一个关闭按钮和一个标题标签 class HeaderView UIView private var titleLabel UILabel private var clo
  • 无法将 _InternalLinkedHashMap 转换为任何内容

    尽管我首先将其作为地图上传 但从 Firebase RealtimeDatabase 获取数据作为地图时遇到了一些问题 我看到的所有解决方案都是您应该将 snapshot value 转换为传入的数据类型 但对我来说没有任何迭代 我已经可以
  • 如何将 MongoDB 与 Solr 集成?

    我以前见过这个问题 但从未收到真正的答案 所以我想知道 有人可以指出我如何将 mongoDB 与 Solr 集成的正确方向吗 我正在寻找伪实时和最终的一致性 做过这件事的人可以透露一些信息吗 如果有帮助的话 我还将 PHP Zend 与 D
  • 如何使用 Rails 2.1 和 MySQL 定义 BigInt 主键?

    从 Rails 2 1 开始 如果您在迁移中定义一个新列 其类型设置为 integer 且 limit 设置为 5 或更多 则在 MySQL 数据库中实际创建的列将是 BigInt 类型 那很完美 但我不知道如何创建具有 BigInt 主键
  • 高级错误处理

    我最近摆了个姿势这个问题 https stackoverflow com questions 15295004 disregarding simple warnings errors in trycatch noredirect 1 com
  • 使用 Java 为 Blogger API 验证自己的 Google 帐户

    我想编写一个将本地文件发布到 Google Blogger 的机器人 我将是唯一使用此应用程序的人 因此我不需要设置用户友好的身份验证例程 我花了一个晚上尝试进行设置 但仍然在处理 OAuth 请求方面遇到困难 我创建了一个新的 Googl
  • 现代 OpenGL 相当于 glBegin/glEnd 的是什么

    我正在为 OpenGL 构建一个图形 API 它基于基本的调用绘制图形样式 基本上 不是将数据存储到 GPU 中 并使用它的句柄调用它 而是提供信息来绘制每次更新应该绘制的内容 我知道它很慢 但它很简单 而且适用于非性能关键型应用程序 无论
  • 正则表达式:如何匹配不仅仅是数字的字符串

    是否可以编写一个正则表达式来匹配所有不匹配的字符串only包含数字 如果我们有这些字符串 abc a4c 4bc ab4 123 它应该匹配第一个 但不是最后一个 我尝试在 RegexBuddy 中摆弄前瞻之类的东西 但我似乎无法弄清楚 d
  • 如何在关系数据库中建模多语言实体

    如果我们要开发一个多语言应用程序 我们应该将翻译存储在资源文件 or the database 假设我们选择在数据库中进行 是否有一种标准方法来建模多语言实体关系模型 1 一张大翻译表 我们可以将所有翻译存储在一张表中并使用语言中立键为属性
  • Flexbox行:不根据内容增长? [复制]

    这个问题在这里已经有答案了 我有以下结构 我想了解为什么我的行不随其内部内容增长 row border solid red display flex flex direction row cell border solid green fl
  • 在 Maps API 浏览器上设置 HTTP Referrer 会导致 403 错误

    我对 HTTP Referrer 设置如何在 Google Maps API 浏览器密钥上工作感到困惑 我正在构建一个网页 以编程方式从 Google 地图请求图像 主要是 Google 地图街景图像 API 但也从 Javascript
  • spring-boot-starter-web 和 spring-boot-starter-webflux 不能一起工作吗?

    当我开始学习spring webflux 我对这个组件有疑问 我建立了一个简单的项目 使用maven来管理它 我添加了相关的依赖项spring boot starter web and spring boot starter webflux
  • Rufus 调度程序未登录生产环境

    我的 Rails 应用程序在初始化程序中使用 rufus scheduler 启动一个进程 这是初始化程序代码的精简版本 config logger isn t available here so we have to grab it fr
  • React 将 JQuery 代码应用于组件内的元素

    我有一个正在使用 React 的应用程序 我现在遇到一个问题 我正在尝试实施bootstrap 所见即所得 bootstrap3 所见即所得 https github com bootstrap wysiwyg bootstrap3 wys
  • 自动删除SQS队列

    有没有办法完全自动删除 SQS 队列 我有一个解决方案 其中服务器在启动时创建 SQS 并订阅 SNS 主题 然而 可能存在服务器崩溃且无法恢复的情况 在这种情况下 我会用另一台服务器替换该服务器 该服务器会在启动时创建自己的队列 现在之前
  • 对多个区域使用 Matcher.appendReplacement()

    java Matcher appendReplacement 方法 带有appendTail 应该让我将源文本转换为结果文本 同时替换所有出现的模式 伪语言的算法类似于 while Matcher find call Matcher app