您可以使用 LINQ 变得美观且富有表现力。
为了使用它,请确保您using System.Linq
的代码顶部有一个。
假如说
source
是存储的目标模式
test
是要测试的字符串。
然后你可以做
public static bool IsValid(string source, string test)
{
return test != null
&& source != null
&& test.Length == source.Length
&& test.Where((x,i) => source[i] != x).Count() <=2
}
还有一个快捷版本在失败时退出 false,从而节省了对字符串其余部分的迭代。
public static bool IsValid(string source, string test)
{
return test != null
&& source != null
&& test.Length == source.Length
&& !test.Where((x,i) => source[i] != x).Skip(2).Any();
}
根据评论中的要求,稍微解释一下这是如何工作的
在 C# 中,可以将字符串视为字符数组,这意味着可以在其上使用 Linq 方法。
test.Where((x,i) => source[i] != x)
这对测试中的每个字符使用 Where 的重载,x
分配给字符并i
分配给索引。如果源中位置 i 处的条件字符不等于 x,则输出到结果中。
Skip(2)
这会跳过前 2 个结果。
Any()
如果还有任何结果,则返回 true,否则返回 false。因为 linq 在 this 为 false 的那一刻推迟执行,所以函数退出而不是评估字符串的其余部分。
然后通过前缀“!”来否定整个测试 表示我们想知道哪里没有更多的结果。
现在为了匹配为子字符串,您需要表现得类似于正则表达式回溯......
public static IEnumerable<int> GetMatches(string source, string test)
{
return from i in Enumerable.Range(0,test.Length - source.Length)
where IsValid(source, !test.Skip(i).Take(source.Length))
select i;
}
public static bool IsValid(string source, IEnumerable<char> test)
{
return test.Where((x,i) => source[i] != x).Skip(2).Any();
}
更新解释
Enumerable.Range(0,test.Length - source.Length)
这会创建一个从 0 到 test.Length - source.Length 的数字序列,不需要从 test 中的每个字符开始检查,因为一旦长度变短,答案就无效。
从我...
基本上迭代集合,每次都将 i 分配为当前值
其中 IsValid(source, !test.Skip(i).Take(source.Length))
过滤结果以仅包括在测试中从索引 i 开始(因此跳过)并继续 source.Length 字符(因此 take.Length 字符)匹配的结果。
选择我
返回我
这将返回一个可枚举的测试中存在匹配项的索引,您可以使用
GetMatches(source,test).Select(i =>
new string(test.Skip(i).Take(source.Length).ToArray()));