亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

.NET中字符串比較的最佳用法

 更新時間:2022年02月08日 10:39:25   作者:痕跡g  
本文詳細講解了.NET中字符串比較的最佳用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

.NET 為開發(fā)本地化和全球化應用程序提供廣泛支持,在執(zhí)行排序和顯示字符串等常見操作時,輕松應用當前區(qū)域性或特定區(qū)域性的約定。 但排序或比較字符串并不總是區(qū)分區(qū)域性的操作。

例如,對于應用程序內(nèi)部使用的字符串,通常應該跨所有區(qū)域性以相同的方式對其進行處理。 如果將 XML 標記、HTML 標記、用戶名、文件路徑和系統(tǒng)對象名稱等與區(qū)域性無關的字符串數(shù)據(jù)解釋為區(qū)分區(qū)域性,則應用程序代碼會遭遇細微的錯誤、不佳的性能,在某些情況下,還會遭遇安全性問題。

本文介紹 .NET 中的字符串排序、比較和大小寫方法,針對如何選擇適當?shù)淖址幚矸椒ㄌ岢鼋ㄗh,并提供有關字符串處理方法的其他信息。

對字符串用法的建議

使用 .NET 進行開發(fā)時,請遵循以下簡要建議比較字符串:

  • 使用為字符串操作顯式指定字符串比較規(guī)則的重載。 通常情況下,這涉及調(diào)用具有 StringComparison類型的參數(shù)的方法重載。
  • 使用 StringComparison.Ordinal 或 StringComparison.OrdinalIgnoreCase 進行比較,并以此作為匹配區(qū)域性不明確的字符串的安全默認設置。
  • 將比較與 StringComparison.Ordinal 或 StringComparison.OrdinalIgnoreCase 配合使用,以獲得更好的性能。
  • 向用戶顯示輸出時,使用基于 StringComparison.CurrentCulture 的字符串操作。
  • 當進行與語言(例如,符號)無關的比較時,使用非語言的 StringComparison.Ordinal 或 StringComparison.OrdinalIgnoreCase 值,而不使用基于 CultureInfo.InvariantCulture 的字符串操作。
  • 在規(guī)范化要比較的字符串時,使用 String.ToUpperInvariant 方法而非 String.ToLowerInvariant 方法。
  • 使用 String.Equals 方法的重載來測試兩個字符串是否相等。
  • 使用 String.Compare 和 String.CompareTo 方法可對字符串進行排序,而不是檢查字符串是否相等。
  • 在用戶界面,使用區(qū)分區(qū)域性的格式顯示非字符串數(shù)據(jù),如數(shù)字和日期。 使用格式以固定區(qū)域性使非字符串數(shù)據(jù)顯示為字符串形式。

比較字符串時,請避免采用以下做法:

  • 不要使用未顯式或隱式為字符串操作指定字符串比較規(guī)則的重載。
  • 在大多數(shù)情況下,不要使用基于 StringComparison.InvariantCulture 的字符串操作。 其中的一個少數(shù)例外情況是,保存在語言上有意義但區(qū)域性不明確的數(shù)據(jù)。
  • 不要使用 String.Compare 或 CompareTo 方法的重載和用于確定兩個字符串是否相等的返回值為 0 的測試。

顯式指定字符串比較

重載 .NET 中大部分字符串操作方法。 通常,一個或多個重載會接受默認設置,然而其他重載則不接受默認設置,而是定義比較或操作字符串的精確方式。 大多數(shù)不依賴于默認設置的方法都包括 StringComparison類型的參數(shù),該參數(shù)是按區(qū)域性和大小寫為字符串比較顯式指定規(guī)則的枚舉。 下表描述StringComparison 枚舉成員。

StringComparison 成員描述
CurrentCulture使用當前區(qū)域性執(zhí)行區(qū)分大小寫的比較。
CurrentCultureIgnoreCase使用當前區(qū)域性執(zhí)行不區(qū)分大小寫的比較。
InvariantCulture使用固定區(qū)域性執(zhí)行區(qū)分大小寫的比較。
InvariantCultureIgnoreCase使用固定區(qū)域性執(zhí)行不區(qū)分大小寫的比較。
Ordinal執(zhí)行序號比較。
OrdinalIgnoreCase執(zhí)行不區(qū)分大小寫的序號比較。

例如, IndexOf 方法(它返回 String 對象中與某字符或字符串匹配的子字符串的索引)具有九種重載:

  • 默認情況下,IndexOf(Char), IndexOf(Char, Int32)和 IndexOf(Char, Int32, Int32)對字符串中的字符執(zhí)行序號(區(qū)分大小寫但不區(qū)分區(qū)域性的)搜索。
  • 默認情況下,IndexOf(String), IndexOf(String, Int32)和 IndexOf(String, Int32, Int32)對字符串中的子字符串執(zhí)行區(qū)分大小寫且區(qū)分區(qū)域性的搜索。
  • IndexOf(String, StringComparison)、 IndexOf(String, Int32, StringComparison)和 IndexOf(String, Int32, Int32, StringComparison),其中包括 StringComparison 類型的參數(shù),該類型允許指定比較形式。

我們建議選擇不使用默認值的重載,原因如下:

  • 具有默認參數(shù)的一些重載(在字符串實例中搜索 Char 的重載)執(zhí)行序號比較,而其他重載(在字符串實例中搜索字符串的重載)執(zhí)行的是區(qū)分區(qū)域性的比較。 要記住哪種方法使用哪個默認值并非易事,并很容易混淆重載。
  • 依賴于方法調(diào)用默認值的代碼的意圖并不清楚。 在下面依賴于默認值的示例中,很難了解開發(fā)人員對兩個字符串的實際意圖是執(zhí)行序號比較還是語言比較,或者 protocol 和“http”之間存在的大小寫差異是否會導致相等性測試返回 false類型的參數(shù)的方法重載。
string protocol = GetProtocol(url);
if (String.Equals(protocol, "http")) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}

一般情況下,我們建議調(diào)用不依賴于默認設置的方法,因為這會明確代碼的意圖。 這進而使代碼更具可讀性且更易于調(diào)試和維護。 下面的示例解決了前面示例中提出的問題。 使用序號比較并且忽略大小寫差異。

string protocol = GetProtocol(url);
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}

字符串比較的詳細信息

字符串比較是許多字符串相關操作的核心,特別是排序和相等性測試操作。 字符串以確定的順序進行排序:如果在排序的字符串列表中,“my”出現(xiàn)在“string”之前,則“my”必定小于或等于“string”。 此外,比較可隱式確定相等性。 對于認為是相等的字符串,比較操作將返回零。 對此很好的解釋是兩個字符串都不小于對方。 涉及到字符串的最有意義的操作包括這些步驟中的一個或兩個步驟:與另一個字符串進行比較和執(zhí)行明確的排序操作。

[!NOTE]

可以下載排序權重表,這是一組文本文件,其中包含有關 Windows 操作系統(tǒng)排序和比較操作中所使用的字符權重的信息,也可以下載默認 Unicode 排序元素表,這是適用于 Linux 和 macOS 的最新版排序權重表。 Linux 和 macOS 上的特定排序權重表版本取決于系統(tǒng)上安裝的 International Components for Unicode 庫的版本。 有關 ICU 版本及它們所實現(xiàn)的 Unicode 版本的信息,請參閱下載 ICU。

但是,評估兩個字符串的相等性或排序順序不會生成一個正確的結果;其結果取決于用于比較這兩個字符串的條件。 特別是,序號或基于當前區(qū)域性或固定區(qū)域性(基于英語語言的區(qū)域設置不明確的區(qū)域性)的大小寫和排序約定的字符串比較可能會產(chǎn)生不同的結果。

此外,使用不同 .NET 版本或在不同操作系統(tǒng)或不同的操作系統(tǒng)版本上使用 .NET 進行字符串比較時,返回的結果可能不同。 有關詳細信息,請參閱字符串和 Unicode 標準。

使用當前區(qū)域性的字符串比較

一個條件涉及在比較字符串時使用當前區(qū)域性的約定。 基于當前區(qū)域性的比較使用線程的當前區(qū)域性或區(qū)域設置。 如果用戶未設置該區(qū)域性,則默認為“控制面板”中“區(qū)域選項” 窗口中的設置。 當數(shù)據(jù)與語言相關并反映區(qū)分區(qū)域性的用戶交互時,應始終使用基于當前區(qū)域性的比較。

但是,當區(qū)域性發(fā)生更改時,.NET 中的比較和大小寫行為也發(fā)生更改。 如果執(zhí)行應用程序的計算機與用于開發(fā)該應用程序的計算機具有不同的區(qū)域性,或者執(zhí)行線程改變它的區(qū)域性,則會發(fā)生這種情況。 此行為是有意而為之的,但許多開發(fā)人員不易察覺此行為。 下面的示例說明了美國英語(“en-US”)與瑞典語(“sv-SE”)區(qū)域性在排序順序中的差異。 請注意,單詞“ångström”、“Windows”和“Visual Studio”將出現(xiàn)在已排序的字符串數(shù)組的不同位置。

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string[] values= { "able", "?ngstr?m", "apple", "?ble",
                         "Windows", "Visual Studio" };
      Array.Sort(values);
      DisplayArray(values);

      // Change culture to Swedish (Sweden).
      string originalCulture = CultureInfo.CurrentCulture.Name;
      Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
      Array.Sort(values);
      DisplayArray(values);

      // Restore the original culture.
      Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
    }

    private static void DisplayArray(string[] values)
    {
      Console.WriteLine("Sorting using the {0} culture:",
                        CultureInfo.CurrentCulture.Name);
      foreach (string value in values)
         Console.WriteLine("   {0}", value);

      Console.WriteLine();
    }
}
// The example displays the following output:
//       Sorting using the en-US culture:
//          able
//          ?ble
//          ?ngstr?m
//          apple
//          Visual Studio
//          Windows
//
//       Sorting using the sv-SE culture:
//          able
//          ?ble
//          apple
//          Windows
//          Visual Studio
//          ?ngstr?m

使用當前區(qū)域性的不區(qū)分大小寫比較和區(qū)分區(qū)域性的比較是相同的,只不過前者忽略由線程的當前區(qū)域性指示的大小寫。 這種情況也可表明它的排序順序。

以下方法默認利用使用當前區(qū)域性語義的比較:

  • 不包括String.Compare 參數(shù)的 StringComparison 重載。
  • String.CompareTo 重載。
  • 默認 String.StartsWith(String) 方法和具有 String.StartsWith(String, Boolean, CultureInfo) null nullCultureInfo 重載。
  • 默認 String.EndsWith(String) 方法和需要使用 nullCultureInfo 參數(shù)的 String.EndsWith(String, Boolean, CultureInfo) 方法。
  • 接受String.IndexOf 作為搜索參數(shù)且不包含 String 參數(shù)的 StringComparison 重載。
  • 接受String.LastIndexOf 作為搜索參數(shù)且不包含 String 參數(shù)的 StringComparison 重載。

總之,我們建議調(diào)用具有 <xref:System.StringComparison> 參數(shù)的重載,以便明確方法調(diào)用的意圖。

當從語言角度解釋非語言的字符串數(shù)據(jù),或利用其他區(qū)域性的約定解釋某個特定區(qū)域性中的字符串時,則會發(fā)生或大或小的錯誤。 土耳其語 I 問題便是一個規(guī)范示例。

對于幾乎所有拉丁字母來講(包括美國英語),字符“i”(\u0069) 是字符“I”(\u0049) 的小寫形式。 此大小寫規(guī)則快速成為在此類區(qū)域性中編程的人員的默認設置。 但是,土耳其語(“tr-TR”)字母表中包含一個“帶有點的 I”的字符“?”(\u0130),該字符是“i”的大寫形式。 土耳其語還包括一個小寫“不帶點的 i”字符,即為“?”(\u0131),該字符的大寫形式為“I”。 阿塞拜疆語(“az”)區(qū)域也會出現(xiàn)這種情況。

因此,關于將“i”變?yōu)榇髮懟驅(qū)?ldquo;I”變?yōu)樾懙募僭O并非在所有區(qū)域性中都是有效的。 如果為字符串比較例程使用默認重載,則它們可能會因區(qū)域性不同而異。 如果對非語言的數(shù)據(jù)進行比較,使用默認重載會產(chǎn)生不良后果,如以下對字符串“file”和“FILE”執(zhí)行不區(qū)分大小寫的比較嘗試所示。

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string fileUrl = "file";
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}",
                       fileUrl.StartsWith("FILE", true, null));
      Console.WriteLine();

      Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}",
                        fileUrl.StartsWith("FILE", true, null));
   }
}
// The example displays the following output:
//       Culture = English (United States)
//       (file == FILE) = True
//
//       Culture = Turkish (Turkey)
//       (file == FILE) = False

如果無意中在安全敏感設置中使用了區(qū)域性,則此比較會導致發(fā)生重大問題,如以下示例所示。 如果當前區(qū)域性為美國英語,則 IsFileURI("file:") 等方法調(diào)用將返回 true;但如果當前區(qū)域性為土耳其語,則將返回 false。 因此,在土耳其語系統(tǒng)中,有人可能會避開阻止訪問以“FILE:”開頭的不區(qū)分大小寫的安全措施。

public static bool IsFileURI(String path)
{
   return path.StartsWith("FILE:", true, null);
}

在這種情況下,由于“file:”會被解釋為非語言的、不區(qū)分區(qū)域性的標識符,因此,應按照下面的示例所示編寫代碼:

public static bool IsFileURI(string path)
{
   return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}

序號字符串操作

在方法調(diào)用中指定 StringComparison.Ordinal 或 StringComparison.OrdinalIgnoreCase 值表示非語言比較,這種比較忽略了自然語言的特性。 利用 StringComparison 值調(diào)用的方法將字符串操作決策建立在簡單的字節(jié)比較的基礎之上,而不是按區(qū)域性參數(shù)化的大小寫或相等表。 在大多數(shù)情況下,這種方法最符合字符串的預期解釋,并使代碼更快更可靠。

序號比較就是字符串比較,在這種比較中,將比較每個字符串中的每個字節(jié)且不進行語言解釋;例如,“windows”不匹配“Windows”。 實質(zhì)上,這是對 C 運行時 strcmp 函數(shù)的調(diào)用。 當上下文指示應完全匹配字符串或要求保守匹配策略時,請使用這種比較。 此外,序號比較是最快的比較操作,因為它在確定結果時不應用任何語言規(guī)則。

.NET 中的字符串可以包括嵌入的空字符。 序號比較與區(qū)分區(qū)域性的比較(包括使用固定區(qū)域性的比較)之間最明顯的區(qū)別之一是對字符串中嵌入的空字符的處理方式。 當使用 String.Compare 和 String.Equals 方法執(zhí)行區(qū)分區(qū)域性的比較(包括使用固定區(qū)域性的比較)時,將忽略這些字符。 因此,在區(qū)分區(qū)域性的比較中,包含嵌入的空字符的字符串可視為等于不包含空字符的字符串。

[!IMPORTANT]

盡管字符串比較方法忽略嵌入的空字符,但是 String.Contains、 String.EndsWith、 String.IndexOf、 String.LastIndexOf和 String.StartsWith 等字符串搜索方法并不會忽略這些字符。

下面的示例對字符串“Aa”與在“A”和“a”之間嵌入了多個空字符的相似字符串進行區(qū)分區(qū)域性的比較,并顯示如何將這兩個字符串視為相等的字符串:

using System;

public class Example
{
   public static void Main()
   {
      string str1 = "Aa";
      string str2 = "A" + new String('\u0000', 3) + "a";
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):",
                        str1, ShowBytes(str1), str2, ShowBytes(str2));
      Console.WriteLine("   With String.Compare:");
      Console.WriteLine("      Current Culture: {0}",
                        String.Compare(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}",
                        String.Compare(str1, str2, StringComparison.InvariantCulture));

      Console.WriteLine("   With String.Equals:");
      Console.WriteLine("      Current Culture: {0}",
                        String.Equals(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}",
                        String.Equals(str1, str2, StringComparison.InvariantCulture));
   }

   private static string ShowBytes(string str)
   {
      string hexString = String.Empty;
      for (int ctr = 0; ctr < str.Length; ctr++)
      {
         string result = String.Empty;
         result = Convert.ToInt32(str[ctr]).ToString("X4");
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
         hexString += result;
      }
      return hexString.Trim();
   }
}
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Current Culture: 0
//          Invariant Culture: 0
//       With String.Equals:
//          Current Culture: True
//          Invariant Culture: True

但是,當使用序號比較時,這兩個字符串不會視為相等,如下面的示例所示:

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):",
                  str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine("   With String.Compare:");
Console.WriteLine("      Ordinal: {0}",
                  String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine("   With String.Equals:");
Console.WriteLine("      Ordinal: {0}",
                  String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Ordinal: 97
//       With String.Equals:
//          Ordinal: False

不區(qū)分大小寫的序號比較是第二種最保守的方法。 這些比較會忽略大多數(shù)的大小寫;例如,“windows”會匹配“Windows”。 在處理 ASCII 字符時,此策略等同于 StringComparison.Ordinal,只不過它會忽略常用的 ASCII 大小寫。 因此,[A, Z] (\u0041-\u005A) 中的任何字符都會匹配 [a,z] (\u0061-\007A) 中的相應字符。 超出 ASCII 范圍的大小寫使用固定區(qū)域性的表。 因此,下面的比較:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);

等效于(但會更快)這種比較:

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(),
               StringComparison.Ordinal);

這些比較仍非???。

StringComparison.Ordinal 和 StringComparison.OrdinalIgnoreCase 均直接使用二進制值并最適合匹配。 當不確定比較設置時,請使用這兩個值中的其中一個。 不過,由于它們執(zhí)行逐字節(jié)比較,因此不會按照語言排序順序(如英語詞典)進行排序,而是按照二進制排序順序。 如果向用戶顯示結果,則在大多數(shù)上下文中結果都看上去不正常。

序號語義是不包括 String.Equals 參數(shù)(包括相等運算符)的 StringComparison 重載的默認項。 總之,我們建議調(diào)用具有 StringComparison 參數(shù)的重載。

使用固定區(qū)域性的字符串操作

具有固定區(qū)域性的比較使用由靜態(tài) CompareInfo 屬性返回的 CultureInfo.InvariantCulture 屬性。 此行為在所有系統(tǒng)中都相同;它會將其范圍外的任何字符轉(zhuǎn)換為其認為等效的固定字符。 此策略對于在各個區(qū)域性中維護一組字符串行為很有用,但經(jīng)常產(chǎn)生意外的結果。

具有固定區(qū)域性的不區(qū)分大小寫的比較也使用由靜態(tài) CompareInfo 屬性返回的靜態(tài) CultureInfo.InvariantCulture 屬性以獲取比較信息。 所轉(zhuǎn)換字符中的任何大小寫差異都將被忽略。

使用 StringComparison.InvariantCulture 和 StringComparison.Ordinal 的比較對 ASCII 字符串產(chǎn)生相同的作用。 但是, StringComparison.InvariantCulture 會做出可能不適用于解釋為一組字節(jié)的字符串的語言性決策。 還可以使用 CultureInfo.InvariantCulture.CompareInfo 對象使 Compare 方法將一組特定的字符解釋為等效字符。 例如,下面的等效字符在固定區(qū)域性中是有效的:

InvariantCulture: a + ? = å

如果 A 字符的小寫拉丁字母“a”(\u0061) 旁邊有上方組合圓圈字符“+ " ?”(\u030a),A 字符就會被解釋為,上方帶有圓圈的小寫拉丁字母“å”(\u00e5)。 如下面的示例所示,此行為不同于序號比較。

string separated = "\u0061\u030a";
string combined = "\u00e5";

Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
                  separated, combined,
                  String.Compare(separated, combined,
                                 StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
                  separated, combined,
                  String.Compare(separated, combined,
                                 StringComparison.Ordinal) == 0);
// The example displays the following output:
//    Equal sort weight of a° and ? using InvariantCulture: True
//    Equal sort weight of a° and ? using Ordinal: False

當解釋其中出現(xiàn)如“å”組合的文件名稱、cookie 或其他內(nèi)容時,序號比較仍會提供最透明和最合適的行為。

總的來說,固定區(qū)域性具有極少的對比較有用的屬性。 它會以與語言相關的方式執(zhí)行比較,使其無法保證完整的符號等效性,但它并不是任何區(qū)域性中顯示的選擇。 使用 StringComparison.InvariantCulture 進行比較的其中一個原因是為多個區(qū)域性相同的顯示保留已排序的數(shù)據(jù)。 例如,如果應用程序附帶包含用于顯示的已排序標識符列表的大型數(shù)據(jù)文件,則添加到此列表將需要使用固定條件樣式排序插入。

為方法調(diào)用選擇 StringComparison 成員

下表概述了從語義字符串上下文到 StringComparison 枚舉成員的映射:

數(shù)據(jù)行為相應 System.StringComparison

value

區(qū)分大小寫的內(nèi)部標識符。

區(qū)分大小寫的標準標識符(例如 XML 和 HTTP)。

區(qū)分大小寫的安全相關設置。

字節(jié)完全匹配的非語言標識符。Ordinal
不區(qū)分大小寫的內(nèi)部標識符。

不區(qū)分大小寫的標準標識符(例如 XML 和 HTTP)。

文件路徑。

注冊表項和值。

環(huán)境變量。

資源標識符(例如,句柄名稱)。

不區(qū)分大小寫的安全相關設置。

無關大小寫的非語言標識符;尤其是存儲在大多數(shù) Windows 系統(tǒng)服務中的數(shù)據(jù)。OrdinalIgnoreCase
某些保留的、與語言相關的數(shù)據(jù)。

需要固定排序順序的語言數(shù)據(jù)的顯示。

仍與語言相關的區(qū)域性不明確數(shù)據(jù)。InvariantCulture

- 或 -

InvariantCultureIgnoreCase

向用戶顯示的數(shù)據(jù)。

大多數(shù)用戶輸入。

需要本地語言自定義的數(shù)據(jù)。CurrentCulture

- 或 -

CurrentCultureIgnoreCase

.NET 中的常見字符串比較方法

以下各節(jié)介紹最常用于執(zhí)行字符串比較的方法。

String.Compare

默認解釋: StringComparison.CurrentCulture。

作為字符串解釋最核心的操作,應根據(jù)當前區(qū)域性檢查這些方法調(diào)用的所有實例來確定是否應該從區(qū)域性(符號)解釋或分離字符串。 通常情況下,采用后者,并且應改用 StringComparison.Ordinal 比較。

System.Globalization.CompareInfo 屬性返回的 CultureInfo.CompareInfo 類也包括利用 Compare 標記枚舉的方式提供大量匹配選項(序號、忽略空白、忽略假名類型等)的 CompareOptions 方法。

String.CompareTo

默認解釋: StringComparison.CurrentCulture。

此方法當前不提供指定 StringComparison 類型的重載。 通常可以將此方法轉(zhuǎn)換為建議的 String.Compare(String, String, StringComparison) 形式。

實現(xiàn) IComparable 和 IComparable 接口的類型實現(xiàn)此方法。 由于它不提供 StringComparison 參數(shù)選項,因此實現(xiàn)類型經(jīng)常使用戶在其構造函數(shù)中指定 StringComparer。 下面的示例定義 FileName 類,其類構造函數(shù)包括 StringComparer 參數(shù)。 然后此 StringComparer 對象將用于 FileName.CompareTo 方法。

using System;

public class FileName : IComparable
{
   string fname;
   StringComparer comparer;

   public FileName(string name, StringComparer comparer)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("name");

      this.fname = name;

      if (comparer != null)
         this.comparer = comparer;
      else
         this.comparer = StringComparer.OrdinalIgnoreCase;
   }

   public string Name
   {
      get { return fname; }
   }

   public int CompareTo(object obj)
   {
      if (obj == null) return 1;

      if (! (obj is FileName))
         return comparer.Compare(this.fname, obj.ToString());
      else
         return comparer.Compare(this.fname, ((FileName) obj).Name);
   }
}

String.Equals

默認解釋: StringComparison.Ordinal。

String 類可通過調(diào)用靜態(tài)或?qū)嵗?Equals 方法重載或使用靜態(tài)相等運算符,測試是否相等。 默認情況下,重載和運算符使用序號比較。 但是,我們?nèi)匀唤ㄗh調(diào)用顯式指定 StringComparison 類型的重載,即使想要執(zhí)行序號比較;這將更輕松地搜索特定字符串解釋的代碼。

String.ToUpper 和 String.ToLower

默認解釋: StringComparison.CurrentCulture。

應謹慎使用這些方法,因為將字符串強制為大寫或小寫經(jīng)常用作在不考慮大小寫的情況下比較字符串的較小規(guī)范化。 如果是這樣,請考慮使用不區(qū)分大小寫的比較。

還可以使用 String.ToUpperInvariant 和 String.ToLowerInvariant 方法。 ToUpperInvariant 是規(guī)范化大小寫的標準方式。 使用 StringComparison.OrdinalIgnoreCase 進行的比較在行為上是兩個調(diào)用的組合:對兩個字符串參數(shù)調(diào)用 ToUpperInvariant ,并使用 StringComparison.Ordinal執(zhí)行比較。

通過向方法傳遞表示區(qū)域性的 CultureInfo 對象,重載也已可用于轉(zhuǎn)換該特性區(qū)域性中的大寫和小寫字母。

Char.ToUpper 和 Char.ToLower

默認解釋: StringComparison.CurrentCulture。

這些方法的工作原理類似于上一節(jié)中所述的 String.ToUpper 和 String.ToLower 方法。

String.StartsWith 和 String.EndsWith

默認解釋: StringComparison.CurrentCulture。

默認情況下,這兩種方法執(zhí)行區(qū)分區(qū)域性的比較。

String.IndexOf 和 String.LastIndexOf

默認解釋: StringComparison.CurrentCulture。

這些方法的默認重載如何執(zhí)行比較方面缺乏一致性。 包含 String.IndexOf 參數(shù)的所有 String.LastIndexOf 和 Char 方法都執(zhí)行序號比較,但是包含 String.IndexOf 參數(shù)的默認 String.LastIndexOf 和 String 方法都執(zhí)行區(qū)分區(qū)域性的比較。

如果調(diào)用 String.IndexOf(String) 或 String.LastIndexOf(String) 方法并向其傳遞一個字符串以在當前實例中查找,那么我們建議調(diào)用顯式指定 StringComparison 類型的重載。 包括 Char 參數(shù)的重載不允許指定 StringComparison 類型。

間接執(zhí)行字符串比較的方法

將字符串比較作為核心操作的一些非字符串方法使用 StringComparer 類型。 StringComparer 類型包含六個返回 StringComparer 實例的靜態(tài)屬性,這些實例的 StringComparer.Compare 方法可執(zhí)行以下類型的字符串比較:

  • 使用當前區(qū)域性的區(qū)分區(qū)域性的字符串比較。 此 StringComparer 對象由 StringComparer.CurrentCulture 屬性返回。
  • 使用當前區(qū)域性的不區(qū)分區(qū)域性的比較。 此 StringComparer 對象由 StringComparer.CurrentCultureIgnoreCase 屬性返回。
  • 使用固定區(qū)域性的單詞比較規(guī)則的不區(qū)分區(qū)域性的比較。 此 StringComparer 對象由 StringComparer.InvariantCulture 屬性返回。
  • 使用固定區(qū)域性的單詞比較規(guī)則的不區(qū)分大小寫和不區(qū)分區(qū)域性的比較。 此 StringComparer 對象由 StringComparer.InvariantCultureIgnoreCase 屬性返回。
  • 序號比較。 此 StringComparer 對象由 StringComparer.Ordinal 屬性返回。
  • 不區(qū)分大小寫的序號比較。 此 StringComparer 對象由 StringComparer.OrdinalIgnoreCase 屬性返回。

Array.Sort 和 Array.BinarySearch

默認解釋: StringComparison.CurrentCulture。

當在集合中存儲任何數(shù)據(jù),或?qū)⒊志脭?shù)據(jù)從文件或數(shù)據(jù)庫中讀取到集合中時,切換當前區(qū)域性可能會使集合中的固定條件無效。 Array.BinarySearch 方法假定已對數(shù)組中要搜索的元素排序。 若要對數(shù)組中的任何字符串元素進行排序, Array.Sort 方法會調(diào)用 String.Compare 方法以對各個元素進行排序。 如果對數(shù)組進行排序和搜索其內(nèi)容的時間范圍內(nèi)區(qū)域性發(fā)生變化,那么使用區(qū)分區(qū)域性的比較器會很危險。 例如在下面的代碼中,是在由 Thread.CurrentThread.CurrentCulture 屬性。 如果在調(diào)用 StoreNames 和 DoesNameExist之間更改了區(qū)域性(尤其是數(shù)組內(nèi)容保存在兩個方法調(diào)用之間的某個位置),那么二進制搜索可能會失敗。

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name) >= 0);  // Line B.
}

建議的變體將顯示在下面使用相同序號(不區(qū)分區(qū)域性)比較方法進行排序并搜索數(shù)組的示例中。 在這兩個示例中,更改代碼會反映在標記 Line A 和 Line B 的代碼行中。

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.Ordinal);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0);  // Line B.
}

如果此數(shù)據(jù)永久保留并跨區(qū)域性移動,并且使用排序來向用戶顯示此數(shù)據(jù),則可以考慮使用 StringComparison.InvariantCulture,其語言操作可獲得更好的用戶輸出且不受區(qū)域性更改的影響。 下面的示例修改了前面兩個示例,使用固定區(qū)域性對數(shù)組進行排序和搜索。

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.InvariantCulture);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0);  // Line B.
}

集合示例:哈希表構造函數(shù)

哈希字符串提供了第二個運算示例,該運算受比較字符串的方式影響。

下面的示例實例化 Hashtable 對象,方法是向其傳遞由 StringComparer 屬性返回的 StringComparer.OrdinalIgnoreCase 對象。 由于派生自 StringComparer 的類 StringComparer 實現(xiàn) IEqualityComparer 接口,其 GetHashCode 方法用于計算哈希表中的字符串的哈希代碼。

const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)
{
   h = new Hashtable(initialTableCapacity,
                     StringComparer.OrdinalIgnoreCase);

   foreach (string file in Directory.GetFiles(directory))
         h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)
{
   Object dt = h[targetFile];
   if (dt != null)
   {
      Console.WriteLine("File {0} was created at time {1}.",
         targetFile,
         (DateTime) dt);
   }
   else
   {
      Console.WriteLine("File {0} does not exist.", targetFile);
   }
}

請參閱

 以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論