gpt4 book ai didi

java - 将 Matcher.appendReplacement() 与多个区域一起使用

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:57:52 25 4
gpt4 key购买 nike

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 示例显示了来自像

这样的输入

dog1 开始 dog2a dog2b 结束 dog3 开始 dog4a dog4b 结束 dog5

你没有得到预期的输出

dog1 开始 cat2a cat2b 结束 dog3 开始 cat4a cat4b 结束 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);
}
}

输出:

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");
}

结果:

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

更新。

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

appendReplacementappendTail 在某种程度上是一种仅向前移动的机制,而 .region() 则不是那么确定。

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

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

接下来,您将区域 10..40 应用到源字符串……然后呢?如果源字符串的那个区域不包含匹配项 - 好的,什么都不做,但是如果它确实包含匹配项? appendReplacement 应该在哪里追加/插入替换结果?结果字符串已经超过 10..40 区域,appendReplacement追加,而不是替换 输出缓冲区中的字符串分区。

如果存在某种约束机制,那么限制区域设置只能设置为类似MAX(start, lastAppendPosition)..MIN(end, sourceLength),那么可以,追加机制可以正常工作,但是.region() 方法没有这样的限制,否则它们(限制)会使 .region() 方法对搜索毫无用处( .region() 方法的主要目的)。

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

关于java - 将 Matcher.appendReplacement() 与多个区域一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32233241/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com