How can I do a case insensitive string comparison? - c#

How can I make the line below case insensitive?
drUser["Enrolled"] =
(enrolledUsers.FindIndex(x => x.Username == (string)drUser["Username"]) != -1);
I was given some advice earlier today that suggested I use:
x.Username.Equals((string)drUser["Username"], StringComparison.OrdinalIgnoreCase)));
the trouble is I can't get this to work, I've tried the line below, this compiles but returns the wrong results, it returns enrolled users as unenrolled and unenrolled users as enrolled.
drUser["Enrolled"] =
(enrolledUsers.FindIndex(x => x.Username.Equals((string)drUser["Username"],
StringComparison.OrdinalIgnoreCase)));
Can anyone point out the problem?

This is not the best practice in .NET framework (4 & +) to check equality
String.Compare(x.Username, (string)drUser["Username"],
StringComparison.OrdinalIgnoreCase) == 0
Use the following instead
String.Equals(x.Username, (string)drUser["Username"],
StringComparison.OrdinalIgnoreCase)
MSDN recommends:
Use an overload of the String.Equals method to test whether two strings are equal.
Use the String.Compare and String.CompareTo methods to sort strings, not to check for equality.

Please use this for comparison:
string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

You should use static String.Compare function like following
x => String.Compare (x.Username, (string)drUser["Username"],
StringComparison.OrdinalIgnoreCase) == 0

Others answer are totally valid here, but somehow it takes some time to type StringComparison.OrdinalIgnoreCase and also using String.Compare.
I've coded simple String extension method, where you could specify if comparison is case sensitive or case senseless with boolean, attaching whole code snippet here:
using System;
/// <summary>
/// String helpers.
/// </summary>
public static class StringExtensions
{
/// <summary>
/// Compares two strings, set ignoreCase to true to ignore case comparison ('A' == 'a')
/// </summary>
public static bool CompareTo(this string strA, string strB, bool ignoreCase)
{
return String.Compare(strA, strB, ignoreCase) == 0;
}
}
After that whole comparison shortens by 10 characters approximately - compare:
Before using String extension:
String.Compare(testFilename, testToStart,true) != 0
After using String extension:
testFilename.CompareTo(testToStart, true)

You can (although controverse) extend System.String to provide a case insensitive comparison extension method:
public static bool CIEquals(this String a, String b) {
return a.Equals(b, StringComparison.CurrentCultureIgnoreCase);
}
and use as such:
x.Username.CIEquals((string)drUser["Username"]);
C# allows you to create extension methods that can serve as syntax suggar in your project, quite useful I'd say.
It's not the answer and I know this question is old and solved, I just wanted to add these bits.

I'd like to write an extension method for EqualsIgnoreCase
public static class StringExtensions
{
public static bool? EqualsIgnoreCase(this string strA, string strB)
{
return strA?.Equals(strB, StringComparison.CurrentCultureIgnoreCase);
}
}

I think you will find more information in this link:
http://codeidol.com/community/dotnet/controlling-case-sensitivity-when-comparing-two-st/8873/
Use the Compare static method on the String class to compare the two strings. Whether the comparison is case-insensitive is determined by the third parameter of one of its overloads. For example:
string lowerCase = "abc";
string upperCase = "AbC";
int caseInsensitiveResult = string.Compare(lowerCase, upperCase,
StringComparison.CurrentCultureIgnoreCase);
int caseSensitiveResult = string.Compare(lowerCase,
StringComparison.CurrentCulture);
The caseSensitiveResult value is -1 (indicating that lowerCase is "less than" upperCase) and the caseInsensitiveResult is zero (indicating that lowerCase "equals" upperCase).

How about using StringComparison.CurrentCultureIgnoreCase instead?

you can always use functions:
.ToLower();
.ToUpper();
convert your strings and then compare them...
Good Luck

Related

How to avoid method overloads for multiple parameter types (else than by using object parameter)?

I am searching for a way how to avoid verbose overloads in case of a method that 1) will always convert parameter to string and 2) should be available for passing other types as parameter.
As always a picture snippet is worth a thousand words and found the following solution resp. example: (i.e. by using an object parameter, which is cast to IFormattable for passing invariant culture)
public static string AppendHexSuffix(this object hexNumber)
{
string hexString = (hexNumber as IFormattable)? // Cast as IFormattable to pass inv cul
.ToString(null, CultureInfo.InvariantCulture) ?? hexNumber.ToString();
if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture)
&& !hexString.EndsWith("h", true, CultureInfo.InvariantCulture))
{
hexString += "h"; // Append hex notation suffix, if missing prefix/suffix
}
return hexString;
}
Although, as far as I've tested, it seems to work fine (correct me if I'm missing something), the upper code doesn't look particularly straight-forward to me and would prefer a more intuitive-looking solution.
Final Question: is there any other more elegant way how to solve this 1) without using the upper object parameter approach and 2) without explicitly declare an overload for each type?
Note: the upper snippet should be take strictly as an example, since the if-statement part, does make sense only in case a "real" string is passed as parameter.
EDIT: After taking into account the answers + comments I've got, and after some more trials, the following final implementation seems to be best-suited for my case:
/// <summary>
/// Converts any type to string and if hex notation prefix/suffix is missing
/// yet still a valid hex number, then appends the hex suffix
/// </summary>
/// <param name="hexNumber">Takes a string, decimal and other types as parameter</param>
/// <returns>Returns input object content as string with hex notation</returns>
public static string AppendHexSuffix<T>(this T hexNumber)
{
// Cast as IFormattable to pass hex format ("X") & invariant culture
var hexString = (hexNumber as IFormattable)?
.ToString("X", CultureInfo.InvariantCulture).Trim() ?? hexNumber.ToString().Trim();
int unused;
if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture)
&& !hexString.EndsWith("h", true, CultureInfo.InvariantCulture)
&& int.TryParse( // No hex prefix/suffix, but still a valid hexadecimal number
hexString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out unused))
{
hexString += "h";
}
return hexString;
}
By this, it also should ignore parameters/objects where hex format makes no sense, as pointed out in the comment from #InBetween. Noteworthy mistake: forgot the "X" format for the first .ToString() call.
You can make use of generics and interface parameters here to always go for the best performance available (avoid boxing) and keep your code DRY.
Lets start off with our common code.
private static string appendHexSuffix(this string hexString)
if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture)
&&
!hexString.EndsWith("h", true, CultureInfo.InvariantCulture))
{
hexString += "h";
}
return hexString;
}
Next lets provide two overloads. First, one for IFormattable.
public static string AppendHexSuffix(this IFormattable hexNumber) =>
appendHexSuffix(hexNumber.ToString(null, CultureInfo.InvariantCulture));
Now our generic for when that method signature doesn't match what we're passing in.
public static string AppendHexSuffix<T>(this T hexNumber) =>
appendHexSuffix(hexNumber.ToString());
Since T can be implied we won't need to specify it, just pretend there's no generic at all.
A little off topic but I'm questioning if you really want this method to accept any kind of object at all. You may be better off with a generic constraint that specifies each type you want to possibly accept. Or maybe an interface. Read about generic constraints here: https://msdn.microsoft.com/en-us/library/d5x73970.aspx
Now you did ask for how to do this without overloads so I'll add this as well, but don't recommend it.
public static string AppendHexSuffix<T>(this T hexNumber)
{
var hexString = (hexNumber as IFormattable)?
.ToString(null, CultureInfo.InvariantCulture) ?? hexNumber.ToString();
if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture)
&& !hexString.EndsWith("h", true, CultureInfo.InvariantCulture))
{
hexString += "h"; // Append hex notation suffix, if missing prefix/suffix
}
return hexString;
}
I think you might be better off using regular expressions for something like this.
First, Convert.ToString will already format the object the way you need, so you can replace that code.
To convert value to its string representation, the method tries to
call the IConvertible.ToString implementation of value. If value does
not implement the IConvertible interface, the method tries to call the
IFormattable.ToString implementation of value. If value does not
implement the IFormattable interface, the method calls the ToString
method of the underlying type of value.
Second, when you need a string to look a certain way, regular expressions are almost always the way to go. They're very fast, too, if you compile them. 99% of the time you want to put a regular expression object in a static variable for this reason. I use Regexr to test regular expressions. It has the additional benefit of gracefully excepting when the string returned is definitely not a hex string.
private static Regex _parser = new Regex(#"(0x)?((\d{2})+)h?", RegexOptions.Compiled);
public static string AppendHexSuffix(this object hexNumber)
{
var hexString = Convert.ToString(hexNumber);
var match = _parser.Match(hexString);
if (!match.Success)
throw new FormatException("Object cannot be converted to a hex format");
return match.Groups[2].Value + "h";
}
#if DEBUG
public static void AppendHexSuffixTest()
{
AppendHexSuffixTest("0x121212", "121212h");
AppendHexSuffixTest("0x121212h", "121212h");
AppendHexSuffixTest("121212h", "121212h");
}
public static void AppendHexSuffixTest(object test, string expected)
{
if (test.AppendHexSuffix() != expected)
throw new Exception("Unit test failed");
}
#endif

string to bool inline conversion

What I currently have:
bool okPress = !string.IsNullOrEmpty(Ctx.Request["okPress"]) &&
Convert.ToBoolean(Ctx.Request["okPress"]);
Correct me if I'm wrong here, but wouldn't this throw a FormatException if the string isn't "true/True" or "false/False"? Is there any way to handle the conversion in one row, without having to worry about exceptions? Or do I need to use Boolean.TryParse?
You can use Boolean.TryParse:
bool okPress;
bool success = Boolean.TryParse(Ctx.Request["okPress"]), out okPress);
For what it's worth, here a "one-liner", create following extension which might be useful especially in LINQ queries:
public static bool TryGetBool(this string item)
{
bool b;
Boolean.TryParse(item, out b);
return b;
}
and write:
bool okPress = Ctx.Request["okPress"].TryGetBool();
IF you didn't want to use TryParse You could do something like
bool okPress = !string.IsNullOrEmpty(Ctx.Request["okPress"]) &&
(Ctx.Request["okPress"].ToLower()=="true");
This way if the string is not true/false it will just assume false for you with no exceptions thrown.
This does of course assume that you are happy for a value of "fish" to be treated as false rather than as an exception.
Better though is to just not do it as a single line. You don't generally have a maximum number of lines of code so two or three simple lines of code are often better than one complicated line of code...
Why don't you compare the string against true?
bool okPress = !string.IsNullOrEmpty(Ctx.Request["okPress"]) &&
String.Compare(Ctx.Request["okPress"], "true", StringComparison.OrdinalIgnoreCase) == 0
You can use TryParse method of Boolean class as you said.
Tries to convert the specified string representation of a logical
value to its Boolean equivalent. A return value indicates whether the
conversion succeeded or failed.
bool result = Boolean.TryParse(Ctx.Request["okPress"]), out okPress);
It returns true if value was converted successfully; otherwise, false.
Your inline conversion.
public static bool TryParseAsBoolean(this string expression)
{
bool booleanValue;
bool.TryParse(expression, out booleanValue);
return booleanValue;
}
bool okPress = Ctx.Request["okPress"].TryParseAsBoolean();

Null and blank values

What's the best way of writing robust code so that a variable can be checked for null and blank.
e.g.
string a;
if((a != null) && (a.Length() > 0))
{
//do some thing with a
}
For strings, there is
if (String.IsNullOrEmpty(a))
You can define an extension method to allow you to do this on many things:
static public bool IsNullOrEmpty<T>(this IEnumerable <T>input)
{
return input == null || input.Count() == 0;
}
It already exists as a static method on the System.String class for strings, as has been pointed out.
And if you are using .NET 4.0 you might want to take a look at String.IsNullOrWhiteSpace.
From version 2.0 you can use IsNullOrEmpty.
string a;
...
if (string.IsNullOrEmpty(a)) ...
if(string.IsNullOrEmpty(string name))
{
/// write ur code
}
for strings:
string a;
if(!String.IsNullOrEmpty(a))
{
//do something with a
}
for specific types you could create an extention method
note that i've used HasValue instead of IsNullorEmpty because 99% of the times you will have to use the !-operator if you use IsNullOrEmpty which I find quite unreadable
public static bool HasValue(this MyType value)
{
//do some testing to see if your specific type is considered filled
}
I find Apache Commons.Lang StringUtils (Java)'s naming a lot easier: isEmpty() checks for null or empty string, isBlank() checks for null, empty string, or whitespace-only. isNullOrEmpty might be more descriptive, but empty and null is, in most cases you use it, the same thing.

String comparison equivalents

I believe these 2 lines are equivalent but after running into a strange issue I no longer believe this to be the case.
String mimeType = context.Request.ContentType;
(String.Compare("text/xml", mimeType, true) == 0))
is the same as :
context.Request.ContentType.ToLower().Equals("text/xml")
Are their implementations in the CLR any different?
They are not equivalent, and ToLower/ToUpper may have some localization issues. The way to compare two strings without case-sensitivity (considering one of the strings may be null, which is why I don't like the str1.Equals method) is the static String.Equals method:
bool areEqual = String.Equals(str1, str2, StringComparison.OrdinalIgnoreCase);
They are not completely equivalent; see here.
Here is the correct way to do a case insensitive comparison:
bool areSame = str1.Equals(str2, StringComparison.OrdinalIgnoreCase);
This way will also be more efficient becasue it doesn't allocate a separate string for the lowercase copy.
In addition to the other answers (#SLaks, #Serhio), I also feel obligated to point out that .ToLower() generates another string. Compare does not as far as I know. Excessive string generation in an app can come back to bite you in terms of memory usage and performance if it is in frequently called code.
the implementation of Compare(string, string, boolean) in .NET:
public static int Compare(string strA, string strB, bool ignoreCase)
{
if (ignoreCase)
{
return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
}
return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
}
and Equals
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public bool Equals(string value)
{
if ((value == null) && (this != null))
{
return false;
}
return EqualsHelper(this, value);
}
So, is NOT the same thing.

Is there a C# case insensitive equals operator?

I know that the following is case sensitive:
if (StringA == StringB) {
So is there an operator which will compare two strings in an insensitive manner?
Try this:
string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);
The best way to compare 2 strings ignoring the case of the letters is to use the String.Equals static method specifying an ordinal ignore case string comparison. This is also the fastest way, much faster than converting the strings to lower or upper case and comparing them after that.
I tested the performance of both approaches and the ordinal ignore case string comparison was more than 9 times faster! It is also more reliable than converting strings to lower or upper case (check out the Turkish i problem). So always use the String.Equals method to compare strings for equality:
String.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);
If you want to perform a culture specific string comparison you can use the following code:
String.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);
Please note that the second example uses the the string comparison logic of the current culture, which makes it slower than the "ordinal ignore case" comparison in the first example, so if you don't need any culture specific string comparison logic and you are after maximum performance, use the "ordinal ignore case" comparison.
For more information, read the full story on my blog.
There are a number of properties on the StringComparer static class that return comparers for any type of case-sensitivity you might want:
StringComparer Properties
For instance, you can call
StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)
or
StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)
It's a bit cleaner than the string.Equals or string.Compare overloads that take a StringComparison argument.
System.Collections.CaseInsensitiveComparer
or
System.StringComparer.OrdinalIgnoreCase
string.Equals(StringA, StringB, StringComparison.CurrentCultureIgnoreCase);
or
if (StringA.Equals(StringB, StringComparison.CurrentCultureIgnoreCase)) {
but you need to be sure that StringA is not null. So probably better tu use:
string.Equals(StringA , StringB, StringComparison.CurrentCultureIgnoreCase);
as John suggested
EDIT: corrected the bug
You can use
if (stringA.equals(StringB, StringComparison.CurrentCultureIgnoreCase))
Operator? NO, but I think you can change your culture so that string comparison is not case-sensitive.
// you'll want to change this...
System.Threading.Thread.CurrentThread.CurrentCulture
// and you'll want to custimize this
System.Globalization.CultureInfo.CompareInfo
I'm confident that it will change the way that strings are being compared by the equals operator.
Here an idea to simplify the syntax:
public class IgnoreCase
{
private readonly string _value;
public IgnoreCase(string s)
{
_value = s;
}
protected bool Equals(IgnoreCase other)
{
return this == other;
}
public override bool Equals(object obj)
{
return obj != null &&
(ReferenceEquals(this, obj) || (obj.GetType() == GetType() && this == (IgnoreCase) obj));
}
public override int GetHashCode()
{
return _value?.GetHashCode() ?? 0;
}
public static bool operator ==(IgnoreCase a, IgnoreCase b)
{
return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
public static bool operator !=(IgnoreCase a, IgnoreCase b)
{
return !(a == b);
}
public static implicit operator string(IgnoreCase s)
{
return s._value;
}
public static implicit operator IgnoreCase(string s)
{
return new IgnoreCase(s);
}
}
Usable like:
Console.WriteLine((IgnoreCase) "a" == "b"); // false
Console.WriteLine((IgnoreCase) "abc" == "abC"); // true
Console.WriteLine((IgnoreCase) "Abc" == "aBc"); // true
Console.WriteLine((IgnoreCase) "ABC" == "ABC"); // true
I am so used to typing at the end of these comparison methods: , StringComparison.
So I made an extension.
namespace System
{ public static class StringExtension
{
public static bool Equals(this string thisString, string compareString,
StringComparison stringComparison)
{
return string.Equals(thisString, compareString, stringComparison);
}
}
}
Just note that you will need to check for null on thisString prior to calling the ext.
string.Compare(string1, string2, true)
Others answer are totally valid here, but somehow it takes some time to type StringComparison.OrdinalIgnoreCase and also using String.Compare.
I've coded simple String extension method, where you could specify if comparison is case sensitive or case senseless with boolean - see following answer:
https://stackoverflow.com/a/49208128/2338477
if (StringA.ToUpperInvariant() == StringB.ToUpperInvariant()) {
People report ToUpperInvariant() is faster than ToLowerInvariant().
//You can make it case insensitive by
s1.ToLower() == s2.ToLower();

Categories

Resources