字符與字符串類型的實踐


分類索引:C# 語言和運行時剖析--前言

 

字符類型


概念:

  • 定義:在.NET Framwork中,字符(Char)類型總是表示成16位Unicode的編碼值。在存儲中間中總是占用兩個字節(Byte)。
  • 說明:在實踐中,直接操作字符類型的場景不是很多,大多數時候字符類型會作為字符串中的一個Item來使用。但在需要控制多國語言或者涉及到需要使用不同的編碼方式序列化字節時,還是需要掌握Unicode和GB(簡體中文)編碼方式中的一些基本知識的。特別是在網絡傳輸中使用得較多。
  • 字符類型可以在需要的情況下與其他類型進行轉化,常見有三種轉化方式,如下:
            Char c;
            Int32 n;

            // 強制轉型,可以使用unchecked/checked關鍵字修飾
            c = (Char)65;
            Console.WriteLine(c);                  // Displays "A"

            n = (Int32)c;
            Console.WriteLine(n);                  // Displays "65"

            c = unchecked((Char)(65536 + 65));
            Console.WriteLine(c);                  // Displays "A"



            // 使用 Convert 輔助類型,在方法中會強制檢查是否數據溢出
            c = Convert.ToChar(65);
            Console.WriteLine(c);                  // Displays "A"

            n = Convert.ToInt32(c);
            Console.WriteLine(n);                  // Displays "65" 


            // 捕獲溢出異常的演示
            try
            {
                c = Convert.ToChar(70000);          // Too big for 16-bits
                Console.WriteLine(c);               // Doesn't execute
            }
            catch (OverflowException)
            {
                Console.WriteLine("Can't convert 70000 to a Char.");
            }


            // 使用 IConvertible 接口的轉型,會發生裝箱,不建議使用
            c = ((IConvertible)65).ToChar(null);
            Console.WriteLine(c);                  // Displays "A"

            n = ((IConvertible)c).ToInt32(null);
            Console.WriteLine(n);                  // Displays "65"
  • 字符類型中定義的其他常用方法。 
        //
        // 摘要:
        //     指示指定的 Unicode 字符是否屬於控制字符類別。
        public static bool IsControl(char c);
        //
        // 摘要:
        //     指示指定的 Unicode 字符是否屬於十進制數字類別。
        public static bool IsDigit(char c);
        // 返回結果:
        //     如果 c 是字母,則為 true;否則為 false。
        public static bool IsLetter(char c);
        // 返回結果:
        //     如果 c 是字母或十進制數字,則為 true;否則為 false。
        public static bool IsLetterOrDigit(char c);
        // 返回結果:
        //     如果 c 是小寫字母,則為 true;否則,為 false。
        public static bool IsLower(char c);
        // 返回結果:
        //     如果 c 是數字,則為 true,否則為 false。
        public static bool IsNumber(char c);
        // 返回結果:
        //     如果 c 是標點符號,則為 true;否則,為 false。
        public static bool IsPunctuation(char c);
        // 返回結果:
        //     如果 c 是分隔符,則為 true;否則,為 false。
        public static bool IsSeparator(char c);
        // 返回結果:
        //     如果 c 是符號字符,則為 true;否則為 false。
        public static bool IsSymbol(char c);
        // 返回結果:
        //     如果 c 是大寫字母,則為 true;否則,為 false。
        public static bool IsUpper(char c);
        // 返回結果:
        //     如果 c 是空白,則為 true;否則,為 false。
        public static bool IsWhiteSpace(char c);
        //
        // 摘要:
        //     將指定字符串的值轉換為它的等效 Unicode 字符。
        public static char Parse(string s);
        //
        // 摘要:
        //     將 Unicode 字符的值轉換為它的小寫等效項。
        public static char ToLower(char c);
        //
        // 摘要:
        //     將此實例的值轉換為其等效的字符串表示形式。
        public override string ToString();
        //
        // 摘要:
        //     將指定的 Unicode 字符轉換為它的等效字符串表示形式。
        public static string ToString(char c);
        //
        // 摘要:
        //     將 Unicode 字符的值轉換為它的大寫等效項。
        public static char ToUpper(char c);
        //
        // 摘要:
        //     將指定字符串的值轉換為它的等效 Unicode 字符。一個指示轉換是否成功的返回代碼。
        // 返回結果:
        //     如果 s 參數成功轉換,則為 true;否則為 false。
        public static bool TryParse(string s, out char result);

 

字符串類型


一. 概念:

  • 定義:一個String類型代表一個不可變的順序字符集合。
  • 說明:
    • 字符串是實踐中使用最多的類型之一。
    • 字符串直接派生自System.Object,屬於引用類型,但跟普通的引用類型有所區別,經常表現出值類型的特征。例如在本系列中<參數的運用>一節中<參數的傳遞>段落中有所講述。
    • 字符串類型與區域設置密切相關,在多國語言環境下的編程時,要密切注意使用不同的區域設置,可能會造成String類型中操作的不同結果。
  • 混淆點
    • 字符串在.NET中是屬於不可變的類型,通常我們認為改變了字符串的值是因為對象指向了一個不同的堆內存地址。
    • 為減少字符串對堆內存的占用,在CLR中有一個字符串留用機制,內存中會保留一個字符串數據的哈希表,每次進行字符串操作,生成新的字符串時,都會在該哈希表中檢查此字符串是否已經存在,如果存在,則返回對已有字符串的引用,而不用創建額外的內存空間。

 

二. 構造字符串:

  • 字符串構造方式:不能使用new()實例構造器構造字符串,一般只能使用直接賦值的方法構造字符串。
  • 高效率構造方式:使用System.Text.StringBuilder類型構造字符串。
    • 優勢:使用鏈式操作或者對同一個字符串對象的多步操作時不會生成若干個string對象的拷貝,而都是在同一個StringBuilder的實例中進行。
    • 常用成員列舉:
成員名稱 成員類型 說明
Capacity 可讀/寫屬性 獲取或設置字符數據的長度(容量)。
Length 可讀/寫屬性 獲取或設置“字符串”中的字符數
ToString 方法 將StringBuilder中容納的字符數組轉化為一個字符串
Chars 索引器屬性 通過[]索引訪問對應的字符
Clear 方法 清除StringBuilder對象的內容
Append 方法 在字符數組末尾最佳單獨一個對象,如果Capacity容量不夠,會自動擴充
Insert 方法 在字符數組中指定的位置插入一個對象
AppendFormat 方法 在字符數組末尾插入指定的帶格式的若干個對象
AppendLine 方法 在字符數組的末尾追加一個行終止符或者一個帶行終止符的字符串
Replace 方法 將字符替換為指定的字符,或將字符串替換為指定的字符串
Remove 方法 從字符數組中刪除指定范圍的字符
CopyTo 方法 將StringBuilder對象中的字符內容的一個子集復制到一個Char數組中

 

三.比較字符串:

  • 一般比較方式:使用String類型定義的靜態方法:Compare, StartWith, EndWith等。
  • 特殊比較方式:使用System.Globalization.CompareInfo類型或者定制該類型的衍生類型來進行字符串的比較。此類型對象可以通過區域性類型System.Globalization.CultureInfo訪問。
  • 實踐中注意:在使用多國語言混合處理時,應該注意使用不同的區域性System.Globalization.CultureInfo所造成的結果可能大大不同,這個時候應該盡量使用上述的第二種方法指定區域性來比較字符串。示例如下:

     

internal static class ComparingStringForEquality {
   public static void Go() {
      String s1 = "Strasse";
      String s2 = "Straße";
      Boolean eq;

      // CompareOrdinal returns nonzero.
      eq = String.Compare(s1, s2, StringComparison.Ordinal) == 0;
      Console.WriteLine("Ordinal  comparison: '{0}' {2} '{1}'", s1, s2,
         eq ? "==" : "!=");

      // Compare Strings appropriately for people 
      // who speak German (de) in Germany (DE)
      CultureInfo ci = new CultureInfo("de-DE");

      // Compare returns zero.
      eq = String.Compare(s1, s2, true, ci) == 0;
      Console.WriteLine("Cultural comparison: '{0}' {2} '{1}'", s1, s2,
         eq ? "==" : "!=");
   }
}

internal static class ComparingStringsForSorting {
   public static void Go() {
      String output = String.Empty;
      String[] symbol = new String[] { "<", "=", ">" };
      Int32 x;
      CultureInfo ci;

      // The code below demonstrates how strings compare 
      // differently for different cultures.
      String s1 = "coté";
      String s2 = "côte";

      // Sorting strings for French in France.
      ci = new CultureInfo("fr-FR");
      x = Math.Sign(ci.CompareInfo.Compare(s1, s2));
      output += String.Format("{0} Compare: {1} {3} {2}",
         ci.Name, s1, s2, symbol[x + 1]);
      output += Environment.NewLine;

      // Sorting strings for Japanese in Japan.
      ci = new CultureInfo("ja-JP");
      x = Math.Sign(ci.CompareInfo.Compare(s1, s2));
      output += String.Format("{0} Compare: {1} {3} {2}",
         ci.Name, s1, s2, symbol[x + 1]);
      output += Environment.NewLine;

      // Sorting strings for the thread's culture
      ci = Thread.CurrentThread.CurrentCulture;
      x = Math.Sign(ci.CompareInfo.Compare(s1, s2));
      output += String.Format("{0} Compare: {1} {3} {2}",
         ci.Name, s1, s2, symbol[x + 1]);
      output += Environment.NewLine + Environment.NewLine;

      // The code below demonstrates how to use CompareInfo.Compare's
      // advanced options with 2 Japanese strings. One string represents
      // the word "shinkansen" (the name for the Japanese high-speed 
      // train) in hiragana (one subtype of Japanese writing), and the 
      // other represents the same word in katakana (another subtype of 
      // Japanese writing).
      s1 = "しんかんせん";  // ("\u3057\u3093\u304B\u3093\u305b\u3093")
      s2 = "シンカンセン";  // ("\u30b7\u30f3\u30ab\u30f3\u30bb\u30f3")

      // Here is the result of a default comparison
      ci = new CultureInfo("ja-JP");
      x = Math.Sign(String.Compare(s1, s2, true, ci));
      output += String.Format("Simple {0} Compare: {1} {3} {2}",
         ci.Name, s1, s2, symbol[x + 1]);
      output += Environment.NewLine;

      // Here is the result of a comparison that ignores 
      // kana type (a type of Japanese writing)
      CompareInfo compareInfo = CompareInfo.GetCompareInfo("ja-JP");
      x = Math.Sign(compareInfo.Compare(s1, s2, CompareOptions.IgnoreKanaType));
      output += String.Format("Advanced {0} Compare: {1} {3} {2}",
         ci.Name, s1, s2, symbol[x + 1]);

      MessageBox.Show(output, "Comparing Strings For Sorting");
   }
}

 

四.檢查字符串中的字符和文本元素:

  • 方法:使用String類型中定義的Contains, IndexOf, LastIndexOf, IndexOfAny, ToCharArray等方法。
  • 實踐中注意: 與比較字符串差不多,在處理多國語言時需要注意System.Globalization.CultureInfo的設定,此處也有一個輔助類型System.Globalization.StringInfo提供,使用這個類型可以保證正確的處理多國語言背景下的文本元素。

 

對象與字符串的相互轉化


一.獲取對象的字符串表示:ToString

  • 來源與重載:ToString方法的源定義來源於System.Object,所以在C#中的任何類型都會自動繼承該方法。但在FCL中常用的一些類型都對該方法做了重載,因為繼承的ToString方法將會返回對象所屬類型的全名,這在實踐中基本沒有意義。
  • 指定具體的格式化器:
    • 在ToString方法中,需要指定實現IFormatProvider接口格式化器。
    • 常見的格式化器包括:CultureInfo,NumberFormat, DateTimeFormat等。
    • 如果不指定具體的格式化器,ToString方法將會讀取當前線程關聯的CurrentCulture作為默認的格式化器。

             示例如下:

internal static class Formatting {
   public static void Go() {
      Decimal price = 123.54M;
      String s = price.ToString("C", new CultureInfo("vi-VN"));
      MessageBox.Show(s);

      s = price.ToString("C", CultureInfo.InvariantCulture); 
      MessageBox.Show(s);
   }
}

 

  • 將多個對象格式化為一個字符串

              使用String.Format方法可以同時格式化多個對象為字符串。

              示例如下(使用定制格式化器):          

internal static class CustomFormatter {
   public static void Go() {
      StringBuilder sb = new StringBuilder();
      sb.AppendFormat(new BoldInt32s(), "{0} {1} {2:M}", "Jeff", 123, DateTime.Now);
      Console.WriteLine(sb);
   }

   private sealed class BoldInt32s : IFormatProvider, ICustomFormatter {
      public Object GetFormat(Type formatType) {
         if (formatType == typeof(ICustomFormatter)) return this;
         return Thread.CurrentThread.CurrentCulture.GetFormat(formatType);
      }

      public String Format(String format, Object arg, IFormatProvider formatProvider) {
         String s;

         IFormattable formattable = arg as IFormattable;

         if (formattable == null) s = arg.ToString();
         else s = formattable.ToString(format, formatProvider);

         if (arg.GetType() == typeof(Int32))
            return "<B>" + s + "</B>";
         return s;
      }
   }
}

 

  • 提供定制格式化器:自定義實現接口IFormatProvider的格式化器。

二.解析字符串來獲取對象:Parse

  • 定義: FCL中的一些常用類型,例如所有的數據類型都提供的Parse方法,解析字符串獲取對象。
  • 實踐注意:在實踐中盡量使用TryParse方法,因為類型轉換的原因,使用Parse解析字符串時可能會出現異常,使用TryParse方法可以避免這個異常發生。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM