Есть ли 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 цифры, прежде чем мы найдем не цифру.