C# 带有自定义StringComparer的IndexOf
为什么C# 带有自定义StringComparer的IndexOf,c#,string,comparison,C#,String,Comparison,为什么String.IndexOf(String, StringComparison)需要StringComparison,不允许使用更通用的StringComparier,甚至不允许只使用iComparier或iQualityComparier 我制作了一个自定义的StringComparer来与几个字典一起使用,我想在我的项目的其他部分中使用它,但是如果没有很多扩展方法,我找不到一个很好的方法来实现这一点,如果这些扩展方法能够工作的话 这是我做的比较器。它大致基于这一建议: 还要注意,Mod
String.IndexOf(String, StringComparison)
需要StringComparison
,不允许使用更通用的StringComparier
,甚至不允许只使用iComparier
或iQualityComparier
我制作了一个自定义的StringComparer
来与几个字典一起使用,我想在我的项目的其他部分中使用它,但是如果没有很多扩展方法,我找不到一个很好的方法来实现这一点,如果这些扩展方法能够工作的话
这是我做的比较器。它大致基于这一建议:
还要注意,ModifyString是一个WIP。我希望根据我比较的输入,在那里添加更多内容。我也知道它很贵,但我只是在寻找ATM的解决方案,而不是性能
public class CustomComparer : StringComparer
{
public override int Compare(string x, string y)
{
return StringComparer.Ordinal.Compare(ModifyString(x), ModifyString(y));
}
public override bool Equals(string x, string y)
{
if (ModifyString(x).Equals(ModifyString(y)))
return true;
else
return false;
}
public override int GetHashCode(string obj)
{
if (obj == null)
return 0;
else
return ModifyString(obj).GetHashCode();
}
private string ModifyString(string s)
{
//I know this code is expensive/naaive, your suggestions are welcome.
s = s.ToLowerInvariant();
s = s.Trim();
s = Regex.Replace(s, @"\s+", " ");//replaces all whitespace characters with a single space.
return s;
}
}
对
IEnumerable
使用一个方便的扩展似乎应该已经有了,您可以编写String
扩展来使用StringComparer
。正如注释中所建议的,所有可能的子字符串长度都在每个位置进行测试,因为无法对自定义StringComparer
进行任何假设
public static class IEnumerableExt {
public static T FirstOrDefault<T>(this IEnumerable<T> src, Func<T, bool> testFn, T defval) => src.Where(aT => testFn(aT)).DefaultIfEmpty(defval).First();
}
public static class StringExt {
public static int IndexOf(this string source, string match, StringComparer sc) {
return Enumerable.Range(0, source.Length) // for each position in the string
.FirstOrDefault(i => // find the first position where either
// match is Equals at this position for length of match (or to end of string) or
sc.Equals(source.Substring(i, Math.Min(match.Length, source.Length-i)), match) ||
// match is Equals to on of the substrings beginning at this position
Enumerable.Range(1, source.Length-i-1).Any(ml => sc.Equals(source.Substring(i, ml), match)),
-1 // else return -1 if no position matches
);
}
}
公共静态类IEnumerableExt{
公共静态T FirstOrDefault(此IEnumerable src,Func testFn,T deffal)=>src.Where(aT=>testFn(aT)).DefaultIfEmpty(deffal).First();
}
公共静态类StringExt{
公共静态int IndexOf(此字符串源、字符串匹配、StringComparer sc){
返回字符串中每个位置的可枚举.Range(0,source.Length)//值
.FirstOrDefault(i=>//找到第一个位置,其中
//匹配在此位置等于匹配长度(或到字符串末尾)或
sc.Equals(source.Substring(i,Math.Min(match.Length,source.Length-i)),match)||
//匹配等于从该位置开始的子字符串的on
可枚举的.Range(1,source.Length-i-1).Any(ml=>sc.Equals(source.Substring(i,ml),match)),
-1//else如果没有位置匹配,则返回-1
);
}
}
示例总是很有用的。如何使用完全自定义的比较器进行搜索?您对子字符串的长度或任何内容一无所知。例如,要在“horse”
中搜索“x”
,您会将“x”
与所有长度的子字进行比较吗?我必须假设,使用标准实现的问题是,它可能会假定您的StringComparer可能不具备的条件。使用-1提前退出的优化(例如一个输入为null,另一个不为null)在使用NullMatches WhenTheStartStringBeginsWithTwoZeroessTringComparer
实现时可能无效。如果您有一个StringComparer
,它可以减少重复的字符序列,例如为了查找索引匹配而将“aaabb”改为“ab”,那么它会变得更加混乱。我不确定您将如何确认您正在比较正确的子字符串。“horse”.IndexOf(“x”,…)
。C#源代码是用URL编码的。@DanWilson添加了示例代码。效果非常好。我并不完全明白它是如何工作的,LINQ不是我的强项,但我会在评论中赞扬你,也许会在某个时候弄明白。谢谢大家!@我在代码中添加了一些注释以试图提供帮助。