繁体   English   中英

删除所有出现的指定 substring,甚至是重叠的

[英]Removing all occurrences of the specified substring, even overlapping ones

例如,源字符串是“appleappleapplebanana”,我想删除的模式是“appleapple”。

我希望它删除所有“appleapple”,即使它们重叠,这样只剩下“banana”。

appleappleapplebanana
^^^^^^^^^^              <-first  occurrence
     ^^^^^^^^^^         <-second occurrence     

如果我使用 replaceAll,结果是“applebanana”,因为删除第一个后,剩下的部分只是“applebanana”。

预期成绩:

输入 图案 结果
“苹果香蕉” “苹果苹果” “香蕉”
“苹果香蕉” “苹果苹果” “香蕉”
“苹果苹果香蕉” “苹果苹果” “香蕉”
“苹果香蕉” “苹果苹果” “苹果香蕉”
“aaabbbaaabbbaaa” “aaabbbaaa” “”(空字符串)

我需要处理任意输入模式,因此仅使用replace("apple")是行不通的。

虽然我对此有一个想法:

  1. 获取所有事件(使用 KMP 之类的东西)
  2. 将相应字符标记为“待删除”
  3. 删除标记字符

但是,我想知道是否有更好的(现成的)方法来实现这一目标。


我最终使用上面的想法制作了自己的 function,因为似乎没有公共库或包似乎支持此功能。

起初这个问题有点令人困惑。 更新后,我认为最好提供的示例来说明问题是匹配aaabbbaaabbbaaa中的“模式” aaabbbaaa

aaabbbaaabbbaaa
aaabbbaaa
      aaabbbaaa
      ^-^        < overlapping part
^-------------^  < match this part: 'aaa' is overlapping

如果正则表达式中可以使用“模式”字符串的长度,则可以使用后视

.{1,9}(?<=aaabbbaaa)

这个正则表达式(演示)将匹配从一个到字符串长度的字符,只要aaabbbaaa在后面。 所以这将匹配aaabbbaaa但也匹配bbbaaa ,因为最后一个a之前也有aaabbbaaa ,并且由于长度限制,它不会跳过任何其他 substring。它还将匹配aaabbbaaaaaabbbaaa中的非重叠,但将例如ccc留在aaabbbaaacccaaabbbaaa

tio.run 上的 Java 演示包含长度:

String regex = ".{1," + pat.length() + "}(?<=" + pat + ")";
Pattern p = Pattern.compile(regex);
String result = p.matcher(str).replaceAll("");

对于较长的输入,可以更有效地添加前瞻以开始匹配并将视部分包装到重复组中,至少重复一次:

(?=aaabbbaaa)(?:.{1,9}(?<=aaabbbaaa))+

这几乎可以将性能提高一倍(演示),但与没有 .相比,较短的字符串效率较低 此外,如果输入包含非单词字符,您可以使用\w (单词字符)代替点。

从技术上讲,这是重叠的。

appleapple
     appleappleappleapple
                    appleapple

而且,这是重复的。

appleapple
     appleapple
          appleapple

虽然,您可以将后者称为重叠.
从本质上讲,这不是被认为具有重复质量的模式的属性。
在那一点上它是固有的——多余的——它只是一个描述。

除了String#replace之外,还有String#replaceAll
它使用正则表达式模式作为第一个参数。

您可以使用以下模式来替换重叠的重复值。

(apple)\1+
replaceAll("(apple)\\1+", "")

我不确定是否有办法使用单一模式删除重叠值。
我想这会复杂得多。

您提到“...将相应字符标记为‘待删除’”
这很可能是删除真正重叠值的合乎逻辑的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM