Есть ли String.IndexOf, который использует предикат?

Мне нужно сказать что-то вроде myString.IndexOf(c => !Char.IsDigit(c)), но я не могу найти такой метод в .NET framework. Я что-то пропустил?

Следующие работы, но мой собственный, кажется, немного утомительно:

using System;

class Program
{
    static void Main()
    {
        string text = "555ttt555";
        int nonDigitIndex = text.IndexOf(c => !Char.IsDigit(c));
        Console.WriteLine(nonDigitIndex);
    }
}

static class StringExtensions
{
    public static int IndexOf(this string self, Predicate<char> predicate)
    {
        for (int index = 0; index < self.Length; ++index) {
            if (predicate(self[index])) {
                return index;
            }
        }
        return -1;
    }
}

Ответ 1

MSDN покажет вам все методы и расширения для данного типа: Класс строк MSDN

В настоящее время не существует метода расширения для String, описывающего именно то, что вы предоставили. Как утверждают другие, прокат собственного не является плохим выбором, поскольку другие опции (кроме regex) не так элегантны.

Изменить Я ошибся в эффективности использования regex для поиска индексов...

Ответ 2

Вы ничего не пропустили. Существует не IndexOf в том виде, который вы ищете в рамках. Самое близкое, что вы могли бы сделать, не сворачивая свои собственные, было бы

text
  .Select((c, index) => new { Char = c, Index = index })
  .Where(pair => !Char.IsDigit(pair.Char))
  .Select(pair => pair.Index)
  .FirstOrDefault(-1);

Однако это непросто следовать и вызывает бессмысленные распределения. В этом случае я бы предпочел перевернуть свой собственный IndexOf.

РЕДАКТИРОВАТЬ. Забыл, что FirstOrDefault - это функция, которую я вручную сканировал в своих приложениях и не является частью стандартных библиотек LINQ с этой перегрузкой.

public static T FirstOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) {
  using (var enumerator = enmumerable.GetEnumerator()) {
    if (enumerator.MoveNext()) {
      return enumerator.Current;
    }
    return defaultValue;
}

Вот версия, которая работает без каких-либо пользовательских расширений. Обратите внимание, что это, например, только, пожалуйста, не помещайте это в свое приложение;)

text
  .Select((c, index) => new { Char = c, Index = index })
  .Where(pair => !Char.IsDigit(pair.Char))
  .Select(pair => pair.Index)
  .Concat(Enumerable.Repeat(-1, 1))
  .First();

Ответ 3

Ваше текущее решение лучше, но может сделать что-то вроде...

int c = myString.TakeWhile(c => Char.IsDigit(c)).Count();
return (c == myString.Length) ? -1 : c;

Немного короче и несколько меньше исключений, чем другие предложения здесь, отредактированные, чтобы показать, как обрабатывать -1 случай. Обратите внимание, что предикат является инверсией предиката в вопросе, потому что мы хотим подсчитать, сколько символов ARE цифры, прежде чем мы найдем не цифру.