IndexOf с пользовательским StringComparer - PullRequest
0 голосов
/ 14 мая 2018

Почему String.IndexOf(String, StringComparison) требует StringComparison и не учитывает более общий StringComparer, или даже просто IComparer<T> или IEqualityComparer<T>?

Я сделал пользовательский StringComparer для использованияс несколькими словарями, и я хочу использовать его в других частях моего проекта, но я не могу найти хороший способ сделать это без использования множества методов расширений, если бы они даже работали.

Этосравнил я сделал.Он был основан примерно на этой рекомендации: Реализация пользовательского IComparer со строкой

Также обратите внимание, что ModifyString является WIP.Я ожидаю добавить туда больше, основываясь на том, с чем сравниваю.Я также знаю, что это дорого, но я просто ищу решение банкомата, а не производительность.

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

1 Ответ

0 голосов
/ 15 мая 2018

Используя удобное расширение для 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
                          );
    }
}
...