c# - 替换字符串中的重叠匹配项(正则表达式或字符串操作)
问题描述
我一直在尝试查找给定字符串中所有出现的子字符串,并用另一个子字符串替换特定的出现(条件对于问题并不重要)。我需要的是找到所有的出现(甚至是重叠的),并且能够轻松地替换我选择的一个特定的。
问题是,如果我不使用前瞻,我将找不到重叠的事件(例如,在“aaa”中查找“aa”只会找到第一个“aa”序列,因为第二个与第一个重叠):
var regex = new Regex(Regex.Escape("aa"));
regex.Matches("aaa").Count;
第二行的值: 1 预期: 2
如果我使用前瞻,我会发现所有出现的情况,但替换不起作用(例如,将“a”中的“a”替换为“b”,将导致“ba”而不是“b”):
var regex = new Regex(Regex.Escape("(?=a)"));
regex.Replace("a", "b");
替换结果: ba 预期: b
当然,这些都是简单的示例,可以轻松地展示问题,但我需要它来处理任何示例。我知道我可以轻松地搜索两者,或者手动检查单词,但是这个代码片段会运行很多次,并且需要高效和可读。
关于查找重叠事件同时仍然能够正确替换的任何想法/提示?我什至应该使用正则表达式吗?
解决方案
要获得重叠的结果,您必须将搜索模式移动一个字符,次数与搜索字符串的长度一样多。
假设对于包含(4 个预期匹配)aaaaaa
的 seachrstring 的文本aaa
,将使用搜索模式完成三个正则表达式搜索:
aaa
(2 场比赛)(?<=a)aaa
(1 场比赛)(?<=aa)aaa
(1 场比赛)
同样适用于更复杂的搜索,例如aba
in abababa
。
private static IEnumerable<Match> GetOverlappingMatches(string text, string searchstring)
{
IEnumerable<Match> combinedMatches = Enumerable.Empty<Match>();
for (int i = 0; i < searchstring.Length; i++)
{
combinedMatches = combinedMatches.Concat(GetMatches(text, searchstring, i));
}
return combinedMatches.Distinct(new MatchComparer());
}
private static IEnumerable<Match> GetMatches(string text, string searchstring, int shifts)
{
string lookahead = $"(?<={searchstring.Substring(0, shifts)})";
string pattern = $"{lookahead}{searchstring}";
return Regex.Matches(text, pattern);
}
您还想添加一个MatchComparer
来过滤双重匹配。
public class MatchComparer : IEqualityComparer<Match>
{
public bool Equals(Match x, Match y)
{
return x.Index == y.Index
&& x.Length == y.Length;
}
public int GetHashCode([DisallowNull] Match obj)
{
return obj.Index ^ obj.Length;
}
}
推荐阅读
- javascript - 更新嵌套数组中的值,同时保持原始索引 ES6
- python - 不同型号的Tensorflow Demo iOS App无法正常工作
- swift - 说类型是非可选的,但打印是可选的
- android - DialogFragment 圆角 - 如何设置透明度
- cakephp-2.0 - 无法访问在控制器中检索到的数组中的数据以显示在视图文件中
- javascript - 如何使用动画将对象水平居中?
- android - 如何使用 androjena 0.5 在 android 中执行 Sparql 查询
- powershell - 使用 Powershell 在远程计算机上编辑注册表项
- c++ - C++20 bit_cast 与 reinterpret_cast
- python - Pandas 去重并返回重复的索引列表