C#中字符串的⽐较操作
字符串⽐较是⽐较常⽤的操作,⼀般出于以下两个原因⽐较字符串:
判断相等
字符串排序
查询API判断字符串相等或排序时,由以下⽅法:
public override bool Equals(object obj);
public bool Equals(string value);
public static bool Equals(string a, string b);
public bool Equals(string value, StringComparison comparisonType);
public static bool Equals(string a, string b, StringComparison comparisonType);
public static int Compare(string strA, string strB);
public static int Compare(string strA, string strB, bool ignoreCase);
public static int Compare(string strA, string strB, StringComparison comparisonType);
public static int Compare(string strA, string strB, bool ignoreCase, CultureInfo culture);
public static int Compare(string strA, string strB, CultureInfo culture, CompareOptions options);
public static int Compare(string strA, int indexA, string strB, int indexB, int length);
public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase);
public static int Compare(string strA, int indexA, string strB, int indexB, int length, StringComparison comparisonType);
public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase, CultureInfo culture);
public static int Compare(string strA, int indexA, string strB, int indexB, int length, CultureInfo culture, CompareOptions options);
public static int CompareOrdinal(string strA, string strB);
public static int CompareOrdinal(string strA, int indexA, string strB, int indexB, int length);
public int CompareTo(object value);
public int CompareTo(string strB);
发现上述的⽅法中⼤多都有StringComparison类型的枚举,查询msdn后得到:
现简单写⼀段代码,测试Compare(string strA, string strB, StringComparison comparisonType)⽅法。分别⽤到StringComparison.CurrentCulture 和StringComparison.Ordinal。代码如下:
static void Main(string[] args)
{
string strA = "asdfadsfasdfew我ò啊?地?⽅?的?asd";
string strB = "adsfeaqfaead啊?多à发¢安2德?森-efadsfa";
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000; i++)
{
string.Compare(strA, strB, StringComparison.CurrentCulture);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
for (int i = 0; i < 1000000; i++)
{
string.Compare(strA, strB,StringComparison.Ordinal);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
for (int i = 0; i < 1000000; i++)
{
string.CompareOrdinal(strA, strB);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
执⾏结果如下:
测试结果⾮常明显,StringComparison.Currentculture显式传递了当前语⾔⽂化,⽽传递了String.Ordinal则会忽略指定的语⾔⽂化,这是执⾏字符串最快的⼀种⽅式。使⽤.NET Reflector查看源代码:
public static int Compare(string strA, string strB, StringComparison comparisonType)
{
if ((comparisonType < StringComparison.CurrentCulture) || (comparisonType > StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
}
if (strA == strB)
{
return 0;
}
if (strA == null)
{
return -1;
}
if (strB == null)
{
return 1;
}
switch (comparisonType)
{
case StringComparison.CurrentCulture:
return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
case StringComparison.CurrentCultureIgnoreCase:
return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
case StringComparison.InvariantCulture:
return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
case StringComparison.InvariantCultureIgnoreCase:
return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
case StringComparison.Ordinal:
return CompareOrdinalHelper(strA, strB);
case StringComparison.OrdinalIgnoreCase:
if (!strA.IsAscii() || !strB.IsAscii())
{
return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
}
return CompareOrdinalIgnoreCaseHelper(strA, strB);
}
throw new NotSupportedException(Environment.GetResourceString("NotSupported_StringComparison"));
}
在上例中,同时测试了String的CompareOrdinal⽅法,效率同样惊⼈。查看其源代码后发现与Compare⽅法String.Ordinal源代码⼀样,此⽅法只是Compare⽅法的⼀个特例:
public static int CompareOrdinal(string strA, string strB)
{
if (strA == strB)
{
return 0;
}
if (strA == null)
{
return -1;
}
if (strB == null)
{
return 1;
}
return CompareOrdinalHelper(strA, strB);
}
接下来看看String.CompareTo()⽅法的源代码:
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public int CompareTo(string strB)
{
if (strB == null)
{
return 1;
}
return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, CompareOptions.None);
}
与类型参数为StringComparison.CurrentCulture的Compare⽅法相同。
另外StringComparer也实现了字符串⽐较⽅法Compare()⽅法。直接看源代码:
public int Compare(object x, object y)
字符串比较函数实现{
if (x == y)
{
return 0;
}
if (x == null)
{
return -1;
}
if (y == null)
{
return 1;
}
string str = x as string;
if (str != null)
{
string str2 = y as string;
if (str2 != null)
{
return this.Compare(str, str2);
}
}
IComparable comparable = x as IComparable;
if (comparable == null)
{
throw new ArgumentException(Environment.GetResourceString("Argument_ImplementIComparable"));
}
return comparable.CompareTo(y);
}
如果程序只将字符串⽤于内部编码⽬的,如路径名、⽂件名、URL、环境变量、反射、XML标记等,这些字符串通常只在程序内部使⽤,不会像⽤户展⽰,应该使⽤String.Ordinal或者使⽤String.CompareOrdinal()⽅法
总结及建议:
1. 使⽤显⽰地指定了字符串⽐较规则的重载函数。⼀般来说,需要带有StringComparison类型参数的重载函数
2. 在对未知⽂化的字符串做⽐较时,使⽤StringComparison.Ordinal和StringComparison.OrdinallgnoreCase作为默认值,提⾼性能
3. 在像⽤户输出结果时,使⽤基于StringComparison.CurrentCulture的字符串
4. 使⽤String.Equals的重载版本来测试两个字符串是否相等。
5. 不要使⽤String.Compare或CompareTo的重载版本来检测返回值是否为0来判断字符串是否相等。这两个函数是⽤于字符串⽐较,⽽⾮检查相等性。
6. 在字符串⽐较时,应以String.ToUpperInvariant函数使字符串规范化,⽽不⽤ToLowerInvariant⽅法,因为Microsoft对执⾏⼤写⽐较的代码进⾏了优化。之所以不⽤
ToUpper和ToLower⽅法,是因为其对语⾔⽂化敏感。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论