I\'m using C# and I want to check if a string contains one of ten characters, *, &, # etc etc.
What is the best way?
The following would be the simplest method, in my view:
var match = str.IndexOfAny(new char[] { '*', '&', '#' }) != -1
Or in a possibly easier to read form:
var match = str.IndexOfAny("*&#".ToCharArray()) != -1
Depending on the context and performance required, you may or may not want to cache the char array.
var specialChars = new[] {'\\', '/', ':', '*', '<', '>', '|', '#', '{', '}', '%', '~', '&'};
foreach (var specialChar in specialChars.Where(str.Contains))
{
Console.Write(string.Format("string must not contain {0}", specialChar));
}
If you just want to see if it contains any character, I'd recommend using string.IndexOfAny, as suggested elsewhere.
If you want to verify that a string contains exactly one of the ten characters, and only one, then it gets a bit more complicated. I believe the fastest way would be to check against an Intersection, then check for duplicates.
private static char[] characters = new char [] { '*','&',... };
public static bool ContainsOneCharacter(string text)
{
var intersection = text.Intersect(characters).ToList();
if( intersection.Count != 1)
return false; // Make sure there is only one character in the text
// Get a count of all of the one found character
if (1 == text.Count(t => t == intersection[0]) )
return true;
return false;
}
Thanks to all of you! (And Mainly Jon!): This allowed me to write this:
private static readonly char[] Punctuation = "$€£".ToCharArray();
public static bool IsPrice(this string text)
{
return text.IndexOfAny(Punctuation) >= 0;
}
as I was searching for a good way to detect if a certain string was actually a price or a sentence, like 'Too low to display'.
As others have said, use IndexOfAny. However, I'd use it in this way:
private static readonly char[] Punctuation = "*&#...".ToCharArray();
public static bool ContainsPunctuation(string text)
{
return text.IndexOfAny(Punctuation) >= 0;
}
That way you don't end up creating a new array on each call. The string is also easier to scan than a series of character literals, IMO.
Of course if you're only going to use this once, so the wasted creation isn't a problem, you could either use:
private const string Punctuation = "*&#...";
public static bool ContainsPunctuation(string text)
{
return text.IndexOfAny(Punctuation.ToCharArray()) >= 0;
}
or
public static bool ContainsPunctuation(string text)
{
return text.IndexOfAny("*&#...".ToCharArray()) >= 0;
}
It really depends on which you find more readable, whether you want to use the punctuation characters elsewhere, and how often the method is going to be called.
EDIT: Here's an alternative to Reed Copsey's method for finding out if a string contains exactly one of the characters.
private static readonly HashSet<char> Punctuation = new HashSet<char>("*&#...");
public static bool ContainsOnePunctuationMark(string text)
{
bool seenOne = false;
foreach (char c in text)
{
// TODO: Experiment to see whether HashSet is really faster than
// Array.Contains. If all the punctuation is ASCII, there are other
// alternatives...
if (Punctuation.Contains(c))
{
if (seenOne)
{
return false; // This is the second punctuation character
}
seenOne = true;
}
}
return seenOne;
}
String.IndexOfAny(Char[])
Here is the Microsoft's documentation.