В конечном итоге общая операция «содержит» сводится к такой функции,
///
/// Determines whether the source contains the sequence. ///
/// The type of the items in the sequences.
///
The source enumerator.
///
The sequence enumerator.
///
An equality comparer.
///
/// An empty sequence will return true.
/// The sequence must support
/// if it does not begin the source.
///
///
/// true if the source contains the sequence;
/// otherwise false.
///
public static bool Contains(
IEnumerator sourceEnumerator,
IEnumerator sequenceEnumerator,
IEqualityComparer equalityComparer)
{
if (equalityComparer == null)
{
equalityComparer = EqualityComparer.Default;
}
while (sequenceEnumerator.MoveNext())
{
if (sourceEnumerator.MoveNext())
{
if (!equalityComparer.Equals(
sourceEnumerator.Current,
sequenceEnumerator.Current))
{
sequenceEnumerator.Reset();
}
}
else
{
return false;
}
}
return true;
}
это может быть тривиально обернуто в расширенной версии, принимающей IEnumerable
как это,
public static bool Contains(
this IEnumerable source,
IEnumerable sequence,
IEqualityComparer equalityComparer = null)
{
if (sequence == null)
{
throw new ArgumentNullException("sequence");
}
using(var sequenceEnumerator = sequence.GetEnumerator())
using(var sourceEnumerator = source.GetEnumerator())
{
return Contains(
sourceEnumerator,
sequenceEnumerator,
equalityComparer);
}
}
Теперь, это будет работать для порядкового сравнения любых последовательностей, включая строки, так как string
реализует IEnumerable
,
// The optional parameter ensures the generic overload is invoked
// not the string.Contains() implementation.
"testable".Contains("est", EqualityComparer.Default)
Однако, как мы знаем, строки не являются общими, они специализированы. Есть два ключевых фактора в игре.
- Проблема "кожуха", которая сама по себе имеет различные зависящие от языка крайние случаи.
- Довольно сложный вопрос о том, как набор «Текстовые элементы» (буквы / цифры / символы и т. Д.) ) представлены кодовыми точками Unicode, и какие действительные последовательности символов могут представлять данную строку, подробности раскрыты в , эти и ответы .
Чистый эффект тот же. Строки, которые вы можете утверждать, лингвистически равны, могут быть корректно представлены различными комбинациями символов. Более того, правила действительности меняются между культурами.
Все это приводит к специализированной строковой реализации «Содержит», как это.
using System.Globalization;
public static bool Contains(
this string source,
string value,
CultureInfo culture = null,
CompareOptions options = CompareOptions.None)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
var compareInfo = culture == null ?
CultureInfo.CurrentCulture.CompareInfo :
culture.CompareInfo;
var sourceEnumerator = StringInfo.GetTextElementEnumerator(source);
var sequenceEnumerator = StringInfo.GetTextElementEnumerator(value);
while (sequenceEnumerator.MoveNext())
{
if (sourceEnumerator.MoveNext())
{
if (!(compareInfo.Compare(
sourceEnumerator.Current,
sequenceEnumerator.Current,
options) == 0))
{
sequenceEnumerator.Reset();
}
}
else
{
return false;
}
}
return true;
}
Эта функция может быть использована для выполнения нечувствительного к регистру, специфичного для культуры «содержимого», которое будет работать независимо от нормализации строк. е. г.
"testable".Contains("EST", StringComparer.CurrentCultureIgnoreCase)