C# – Prüfen Sie, ob eine Zeichenfolge eine Teilzeichenfolge aus einer Liste enthält

C# – Prüfen Sie, ob eine Zeichenfolge eine Teilzeichenfolge aus einer Liste enthält

Es gibt viele verschiedene Szenarien, in denen Sie möglicherweise eine Zeichenfolge mit einer Liste von Teilzeichenfolgen vergleichen möchten. Vielleicht haben Sie es mit einer chaotischen Ausnahmebehandlung zu tun und müssen die Ausnahmemeldung mit einer Liste bekannter Fehlermeldungen vergleichen, um festzustellen, ob der Fehler vorübergehend ist oder nicht.

Wenn Sie eine Zeichenfolge auf eine Liste von Teilzeichenfolgen überprüfen müssen, ist der einfachste Ansatz die Verwendung von list.Any() und string.Contains(), wie hier:

using System.Linq;

public static bool ContainsAny(string s, List<string> substrings)
{
	if (string.IsNullOrEmpty(s) || substrings == null)
		return false;

	return substrings.Any(substring => s.Contains(substring, StringComparison.CurrentCultureIgnoreCase));
}
Code language: C# (cs)

In diesem Artikel zeige ich den Nicht-Linq-Ansatz dazu und bespreche dann das damit verbundene Problem der Rückgabe aller übereinstimmenden Teilzeichenfolgen.

Regelschleifenansatz

Hier ist der Nicht-Linq-Ansatz für dieses Problem:

public static bool ContainsAny(string stringToTest, List<string> substrings)
{
	if (string.IsNullOrEmpty(stringToTest) || substrings == null)
		return false;

	foreach (var substring in substrings)
	{
		if (stringToTest.Contains(substring, StringComparison.CurrentCultureIgnoreCase))
			return true;
	}
	return false;
}
Code language: C# (cs)

Es gibt keinen wirklichen Vorteil, dies gegenüber dem Linq-Ansatz zu verwenden. Sie führen beide gleich aus. Es ist eine Frage der Präferenz.

Tests

Hier sind die Tests, die beweisen, dass dieser Code funktioniert. Beachten Sie, dass es mit den Sonderfällen beginnt. Es ist normalerweise eine gute Idee, mit dem Testen von Sonderfällen zu beginnen, damit Sie nicht versehentlich vergessen, sie zu behandeln.

[TestClass()]
public class StringUtilTests
{
	#region Special cases
	[DataRow(null)]
	[DataRow("")]
	[TestMethod()]
	public void ContainsAny_WhenStringIsNullOrEmpty_ReturnsFalse(string stringToTest)
	{
		//arrange
		var substrings = new List<string>() { "a" };

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsFalse(actual);
	}
	[TestMethod()]
	public void ContainsAny_WhenSubstringsListIsNull_ReturnsFalse()
	{
		//arrange
		string stringToTest = "a";
		List<string> substrings = null;

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsFalse(actual);
	}
	[TestMethod()]
	public void ContainsAny_WhenSubstringsListIsEmpty_ReturnsFalse()
	{
		//arrange
		string stringToTest = "a";
		List<string> substrings = new List<string>();

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsFalse(actual);
	}
	#endregion
	[TestMethod()]
	public void ContainsAny_WhenContainsASubstring_ReturnsTrue()
	{
		//arrange
		string stringToTest = "abc";
		List<string> substrings = new List<string>() { "a" };

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsTrue(actual);
	}
	[TestMethod()]
	public void ContainsAny_WhenContainsASubstringWithDifferentCasing_ReturnsTrue()
	{
		//arrange
		string stringToTest = "ABC";
		List<string> substrings = new List<string>() { "a" };

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsTrue(actual);
	}
	[TestMethod()]
	public void ContainsAny_WhenDoesntContainASubtring_ReturnsFalse()
	{
		//arrange
		string stringToTest = "abc";
		List<string> substrings = new List<string>() { "d" };

		//act
		var actual = StringUtil.ContainsAny(stringToTest, substrings);

		//assert
		Assert.IsFalse(actual);
	}

}
Code language: C# (cs)

Gib alle übereinstimmenden Teilstrings zurück

Anstatt zu fragen „Enthält diese Zeichenfolge diese Teilzeichenfolge?“, fragt dieses verwandte Problem „Welche der Teilzeichenfolgen enthält die Zeichenfolge?“. Dies kann nützlich sein, wenn Sie eine Liste der übereinstimmenden Teilzeichenfolgen anzeigen müssen. Nehmen wir beispielsweise an, Sie überprüfen ein Textfeld auf eingeschränkte Wörter und möchten dem Benutzer alle eingeschränkten Wörter anzeigen, damit er weiß, welche gelöscht werden müssen.

Mit Linq

Sie können list.Where() und string.Contains() verwenden, um alle übereinstimmenden Teilstrings zu erhalten, wie folgt:

using System.Linq;

public static IEnumerable<string> WhereContains(string stringToTest, List<string> substrings)
{
	if (string.IsNullOrEmpty(stringToTest) || substrings == null)
		return Enumerable.Empty<string>();

	return substrings.Where(substring => stringToTest.Contains(substring, StringComparison.CurrentCultureIgnoreCase));
}
Code language: C# (cs)

Da diese Methode IEnumerable zurückgibt, müssen Sie Enumerable.Empty().

zurückgeben, wenn Sie früher zurückkehren möchten

Non-Linq, Generatormethode

Hier ist der Nicht-Linq-Weg, um das Problem zu lösen. Dies ist eine Generatormethode, die yield return verwendet um übereinstimmende Teilstrings an den aufrufenden Code zu streamen, sobald sie gefunden werden:

public static IEnumerable<string> WhereContains(string stringToTest, List<string> substrings)
{
	if (string.IsNullOrEmpty(stringToTest) || substrings == null)
	   yield break;

	foreach (var substring in substrings)
	{
		if (stringToTest.Contains(substring, StringComparison.CurrentCultureIgnoreCase))
			yield return substring;
	}
}
Code language: C# (cs)

Um vorzeitig von einer Generatormethode zurückzukehren, müssen Sie yield break verwenden statt einer regulären Rückgabe , andernfalls erhalten Sie den Compiler-Fehler: „Error CS1622 Cannot return a value from an iterator. Verwenden Sie die yield return-Anweisung, um einen Wert zurückzugeben, oder yield break, um die Iteration zu beenden.“

Dies funktioniert genauso wie der Linq-Ansatz.

Hinweis:Sie könnten eine Liste zurückgeben, anstatt eine Aufzählung zurückzugeben, aber dies hat eine etwas schlechtere Leistung.

Tests

Hier sind die Nicht-Sonderfall-Einheitentests für diese WhereContains()-Methode:

[TestMethod()]
public void WhereContains_WhenContainsASubstring_ReturnsIt()
{
	//arrange
	string stringToTest = "abc";
	var substrings = new List<string>() { "a" };

	//act
	var actual = SubstringUtil.WhereContains(stringToTest, substrings);

	//assert
	CollectionAssert.AreEqual(substrings, actual.ToList());
}
[TestMethod()]
public void WhereContains_OnlyReturnsMatchingSubstrings()
{
	//arrange
	string stringToTest = "abc";
	var substrings = new List<string>() { "a", "d" };
	var expected = new List<string>() { "a" };

	//act
	var actual = SubstringUtil.WhereContains(stringToTest, substrings);

	//assert
	CollectionAssert.AreEqual(expected, actual.ToList());
}
[TestMethod()]
public void WhereContains_WhenNoMatching_ReturnEmptyList()
{
	//arrange
	string stringToTest = "abc";
	var substrings = new List<string>() { "d" };
	var expected = new List<string>();

	//act
	var actual = SubstringUtil.WhereContains(stringToTest, substrings);

	//assert
	CollectionAssert.AreEqual(expected, actual.ToList());
}
Code language: C# (cs)