Stringcomparison OrdinalIgnoreCase for true false values - c#

Does this make sense? MyValue can be "true" or "false"
Should it not be Stringcomparison.OrdinalIgnoreCase ?
MyValue.Equals("true", StringComparison.CurrentCultureIgnoreCase))

I would not do that. Just because a string is not equal to "true" does not mean it's equal to "false". This is an easy way to let ugly bugs slip in. I think you should parse the string
bool value;
if(!Boolean.TryParse(MyValue, out value)) {
// it did not parse
}
// it parsed
This is more likely to be correct, and it's more readable. Plus, culture issues just got swept under the rug.

It really depends on your situation and how the rest of your program is crafted. From the docs on OrdinalCompareCase
The StringComparer returned by the OrdinalIgnoreCase property treats the characters in the strings to compare as if they were converted to uppercase using the conventions of the invariant culture, and then performs a simple byte comparison that is independent of language. This is most appropriate when comparing strings that are generated programmatically or when comparing case-insensitive resources such as paths and filenames.
So basically, if the values are culture independent (generated progamatically, etc) use OrdinalIgnoreCase

Bool.Parse
looks better to me.

Related

Why does "\u1FFF:foo".StartsWith(":") return true?

The string "\u1FFF:foo" starts with \u1FFF (or "῿"), right?
So how can these both be true?
"\u1FFF:foo".StartsWith(":") // equals true
"\u1FFF:foo".StartsWith("\u1FFF") // equals true
// alternatively, the same:
"῿:foo".StartsWith(":") // equals true
"῿:foo".StartsWith("῿") // equals true
Does .NET claim that this string starts with two different characters?
And while I find this very surprising and would like to understand the "why", I'm equally interested in how I can force .NET to search exclusively by codepoints instead (using InvariantCulture doesn't seem to do a thing)?
And for comparison, one characters below that, "\u1FFE:foo".StartsWith(":") returns false.
That a string in general might be considered to start with two different strings that are not byte-for-byte identical is not surprising (because Unicode is complicated). For example, these results are almost always going to reflect what a user wants:
"n\u0303".StartsWith("\u00f1") // true
"n\u0303".StartsWith("n") // false
Using System.Globalization.CharUnicodeInfo.GetUnicodeCategory, you can see that '\u1fff' is in the "OtherNotAssigned" category; it's unclear to me whether that should affect string search/sort/comparison operations (it does not appear to affect normalization, that is, the characters remain after normalization).
If you want a byte-for-byte comparison, use StringComparison.Ordinal.
Because you are using String.StartsWith() incorrectly. You should use String.StartsWith (String, StringComparison) overload and StringComparison.Ordinal.
There is no character assigned to \u1FFF. I.e. there is no linguistic meaning attached to this code. See Greek Extended, Range: 1F00–1FFF excerpt from character code tables for Unicode Standard. Best Practices for Using Strings in .NET document from MSDN explicitly states that if you need to compare strings in a manner that ignores features of natural languages then you should use StringComparison.Ordinal:
Specifying the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase value in a method call signifies a non-linguistic comparison in which the features of natural languages are ignored. Methods that are invoked with these StringComparison values base string operation decisions on simple byte comparisons instead of casing or equivalence tables that are parameterized by culture. In most cases, this approach best fits the intended interpretation of strings while making code faster and more reliable.
Moreover, it recommends to always explicitly specify StringComparison in such method calls:
When you develop with .NET, follow these simple recommendations when you use strings:
Use overloads that explicitly specify the string comparison rules for string operations. Typically, this involves calling a method overload that has a parameter of type StringComparison.

Does the culture of the StringComparison type of String.Equals matter?

In C#, you can compare two strings with String.Equals and supply a StringComparison.
I've recently been looking to update my archaic method of comparing ToLower() because I read that it doesn't work on all languages/cultures.
From what I can tell, the comparison types are used to determine order when confronted with a list containing aé and ae as to which should appear first (some cultures order things differently).
With string.Equals, ordering is not important. Therefore is it safe to assume that many of the options are irrelevent, and only [Ordinal] and [Ordinal]IgnoreCase are important?
The MSDN article for String.Equals says
The comparisonType parameter indicates whether the comparison should
use the current or invariant culture, honor or ignore the case of the
two strings being compared, or use word or ordinal sort rules.
string.Equals(myString, theirString, StringComparison.OrdinalIgnoreCase)
I'd also be interested to know how the sort method works internally, does it use String.Compare to work out the relative positioning of two strings?
Case insensitive comparisons are culture dependent. For example using Turkish culture, i is not lowercase for I. With that culture I is paired with ı, and İ is paired with i. See Dotted and dotless I on Wikipedia.
There are a number of weird effects related to culture sensitive string operations. For example "KonNy".StartsWith("Kon") can return false.
So I recommend switching to culture insensitive operations even for seemingly harmless operations.
And even with culture insensitive operations there is plenty of unintuitive behavior in unicode, such as multiple representations of the same glyph, different codepoints that look identical, zero-width characters that are ignored by some operations, but observed by others,...

How to Compare localized strings in C#

I am doing localization for ASP.NET Web Application, when user enters a localized string "XXXX" and i am comparing that string with a value in my localized resource file.
Example :
if ( txtCalender.Text == Resources.START_NOW)
{
//do something
}
But When i do that even when the two strings(localized strings) are equal, it returns false. ie.
txtCalender.Text ="இப்போது தொடங்க"
Resources.START_NOW="இப்போது தொடங்க"
This is localized for Tamil.
Please help..
Use one of the string.Equals overloads that takes a StringComparison value - this allows you to use the current culture for comparison..
if ( txtCalender.Text.Equals(Resources.START_NOW, StringComparison.CurrentCulture))
{
//do something
}
Or, if you want case insensitive comparison:
if ( txtCalender.Text.Equals(Resources.START_NOW,
StringComparison.CurrentCultureIgnoreCase))
{
//do something
}
I found the answer and it works. Here is the solution,
it was not working when i tried from Chrome browser and it works with Firefox. Actually when i converted both string to char array,
txtCalender.Text Returns 40 characters and Resource.START_NOW returned 46. So i have tried to Normalize the string using Normalize() method
if(txtCalender.Text.Normalize() == Resources.START_NOW.Normalize())
It was interpreting one character as two different characters when i didn't put normalize method.
it has worked fine. Thanks for your answers.
You can compare with InvariantCulture in String.Equals (statis method):
String.Equals("XXX", "XXX", StringComparison.InvariantCulture);
Not sure whether this helps though, could others comment on it? I've never come across your actual error.
Use String.Equals or String.Compare.
There is some performance differences between these two. String.Compare is faster than String.Equal because String.Compare is static method and String.Equals is instance method.
String.Equal returns a boolean. String.Compare returns 0 when the strings equal, but if they're different they return a positive or negative number depending on whether the first string is before (less) or after (greater) the second string. Therefore, use String.Equals when you need to know if they are the same or String.Compare when you need to make a decision based on more than equality.
You probably need to use .Equals
if(txt.Calendar.Text.Equals(Resources.START_NOW))
{ //...
And if case-insensitive comparison is what you're after (often is) use StringComparison.OrdinalIgnoreCase as the second argument to the .Equals call.
If this isn't working - then can I suggest you breakpoint the line and check the actual value of Resources.START_NOW - the only possible reason why this equality comparison would fail is if the two strings really aren't the same. So my guess is that your culture management isn't working properly.

string.ToLower() and string.ToLowerInvariant()

What's the difference and when to use what? What's the risk if I always use ToLower() and what's the risk if I always use ToLowerInvariant()?
Depending on the current culture, ToLower might produce a culture specific lowercase letter, that you aren't expecting. Such as producing ınfo without the dot on the i instead of info and thus mucking up string comparisons. For that reason, ToLowerInvariant should be used on any non-language-specific data. When you might have user input that might be in their native language/character-set, would generally be the only time you use ToLower.
See this question for an example of this issue:
C#- ToLower() is sometimes removing dot from the letter "I"
TL;DR:
When working with "content" (e.g. articles, posts, comments, names, places, etc.) use ToLower(). When working with "literals" (e.g. command line arguments, custom grammars, strings that should be enums, etc.) use ToLowerInvariant().
Examples:
=Using ToLowerInvariant incorrectly=
In Turkish, DIŞ means "outside" and diş means "tooth". The proper lower casing of DIŞ is dış. So, if you use ToLowerInvariant incorrectly you may have typos in Turkey.
=Using ToLower incorrectly=
Now pretend you are writing an SQL parser. Somewhere you will have code that looks like:
if(operator.ToLower() == "like")
{
// Handle an SQL LIKE operator
}
The SQL grammar does not change when you change cultures. A Frenchman does not write SÉLECTIONNEZ x DE books instead of SELECT X FROM books. However, in order for the above code to work, a Turkish person would need to write SELECT x FROM books WHERE Author LİKE '%Adams%' (note the dot above the capital i, almost impossible to see). This would be quite frustrating for your Turkish user.
I think this can be useful:
http://msdn.microsoft.com/en-us/library/system.string.tolowerinvariant.aspx
update
If your application depends on the case of a string changing in a predictable way that is unaffected by the current culture, use the ToLowerInvariant method. The ToLowerInvariant method is equivalent to ToLower(CultureInfo.InvariantCulture). The method is recommended when a collection of strings must appear in a predictable order in a user interface control.
also
...ToLower is very similar in most places to ToLowerInvariant. The documents indicate that these methods will only change behavior with Turkish cultures. Also, on Windows systems, the file system is case-insensitive, which further limits its use...
http://www.dotnetperls.com/tolowerinvariant-toupperinvariant
hth
String.ToLower() uses the default culture while String.ToLowerInvariant() uses the invariant culture. So you are essentially asking the differences between invariant culture and ordinal string comparision.

String Case Sensitivity [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Is there a C# case insensitive equals operator?
string string1 = "aBc"
string string2 = "AbC"
how can I check if string1 is equal to string2 and have it return true, regardless of case sensitivity.
Two approaches:
You can .ToLower() and do string-equality, or you can use this:
string.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase)
Edit: To appease the downvoters, this operation is useful if your data is culturally significant (i.e., you're comparing Scandinavian words and your current locale is set correctly). If this data is culturally agnostic, and you don't care about locales (bad idea, particularly since .NET lives for Unicode), you can do this:
string.Equals(string1, string2, StringComparison.OrdinalIgnoreCase)
You should use the recommendations here MSDN: "Recommendations for String Use" :
DO: Use StringComparison.Ordinal or OrdinalIgnoreCase for comparisons as your safe default for culture-agnostic string matching.
DO: Use StringComparison.Ordinal and OrdinalIgnoreCase comparisons for increased speed.
DO: Use StringComparison.CurrentCulture-based string operations when displaying the output to the user.
DO: Switch current use of string operations based on the invariant culture to use the non-linguistic StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase when the comparison is linguistically irrelevant (symbolic, for example).
DO: Use ToUpperInvariant rather than ToLowerInvariant when normalizing strings for comparison.
DON'T: Use overloads for string operations that don't explicitly or implicitly specify the string comparison mechanism.
DON'T: Use StringComparison.InvariantCulture-based string operations in most cases; one of the few exceptions would be persisting linguistically meaningful but culturally-agnostic data.
I must admit they were an eyeopener for me. Especially the last one.
You can also use string.Compare, adding the third parameter, which is ignoreCase:
if (string.Compare(string1, string2, true) == 0)
{
// string are equal
}
And you could use also the CompareInfo class:
if (CultureInfo.CurrentCulture.CompareInfo.Compare(string1, string2,
CompareOptions.IgnoreCase) == 0)
{
// string are equal
}
string.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);
:D
string.Equals("aBc", "AbC", StringComparison.CurrentCultureIgnoreCase)

Categories

Resources