System.Char 结构

本文提供了此 API 参考文档的补充说明。

Char 结构使用 UTF-16 编码表示 Unicode 码位。 对象的值 Char 是它的 16 位数字(序号)值。

如果不熟悉 Unicode、标量值、码位、代理项对、UTF-16 和 Rune 类型,请参阅 .NET 中的字符编码简介。

本文探讨对象与字符之间的关系 Char ,并讨论使用 Char 实例执行的一些常见任务。 建议考虑 . Rune NET Core 3.0 中引入的类型,作为执行其中一些任务的替代方法 Char

Char 对象、Unicode 字符和字符串

对象 String 是表示文本字符串的结构的顺序集合 Char 。 大多数 Unicode 字符都可以由单个 Char 对象表示,但编码为基字符、代理项对和/或组合字符序列的字符由多个 Char 对象表示。 因此, Char 对象中的 String 结构不一定等效于单个 Unicode 字符。

在以下情况下,多个 16 位代码单元用于表示单个 Unicode 字符:

  • 字形,它可能包含单个字符或基字符,后跟一个或多个组合字符。 例如,字符 ä 由 Char 代码单元为 U+0061 的对象表示,后跟 Char 代码单元为 U+0308 的对象。 (字符 ä 也可以由具有 U+00E4 代码单元的单个 Char 对象定义。下面的示例演示字符 ä 由两 Char 个对象组成。

    using System;
    using System.IO;
    
    public class Example1
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter("chars1.txt");
            char[] chars = { '\u0061', '\u0308' };
            string strng = new String(chars);
            sw.WriteLine(strng);
            sw.Close();
        }
    }
    // The example produces the following output:
    //       ä
    
    open System
    open System.IO
    
    let sw = new StreamWriter("chars1.txt")
    let chars = [| '\u0061'; '\u0308' |]
    let string = String chars
    sw.WriteLine string
    sw.Close()
    
    // The example produces the following output:
    //       ä
    
    Imports System.IO
    
    Module Example2
        Public Sub Main()
            Dim sw As New StreamWriter("chars1.txt")
            Dim chars() As Char = {ChrW(&H61), ChrW(&H308)}
            Dim strng As New String(chars)
            sw.WriteLine(strng)
            sw.Close()
        End Sub
    End Module
    ' The example produces the following output:
    '       ä
    
  • Unicode 基本多语言平面外部的字符(BMP)。 除表示平面 0 的 BMP 之外,Unicode 还支持 16 个平面。 Unicode 代码点由包含平面的 21 位值在 UTF-32 中表示。 例如,U+1D160 表示音乐符号第八注字符。 由于 UTF-16 编码只有 16 位,因此 BMP 之外的字符由 UTF-16 中的代理项对表示。 以下示例演示 U+1D160 的 UTF-32 等效项(音乐符号第八音符)为 U+D834 U+DD60。 U+D834 是高代理项;高代理项范围从 U+D800 到 U+DBFF。 U+DD60 是低代理项;低代理项范围从 U+DC00 到 U+DFFF。

    using System;
    using System.IO;
    
    public class Example3
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter(@".\chars2.txt");
            int utf32 = 0x1D160;
            string surrogate = Char.ConvertFromUtf32(utf32);
            sw.WriteLine("U+{0:X6} UTF-32 = {1} ({2}) UTF-16",
                         utf32, surrogate, ShowCodePoints(surrogate));
            sw.Close();
        }
    
        private static string ShowCodePoints(string value)
        {
            string retval = null;
            foreach (var ch in value)
                retval += String.Format("U+{0:X4} ", Convert.ToUInt16(ch));
    
            return retval.Trim();
        }
    }
    // The example produces the following output:
    //       U+01D160 UTF-32 = ð (U+D834 U+DD60) UTF-16
    
    open System
    open System.IO
    
    let showCodePoints (value: char seq) =
        let str =
            value
            |> Seq.map (fun ch -> $"U+{Convert.ToUInt16 ch:X4}")
            |> String.concat ""
        str.Trim()
    
    let sw = new StreamWriter(@".\chars2.txt")
    let utf32 = 0x1D160
    let surrogate = Char.ConvertFromUtf32 utf32
    sw.WriteLine $"U+{utf32:X6} UTF-32 = {surrogate} ({showCodePoints surrogate}) UTF-16"
    sw.Close()
    
    // The example produces the following output:
    //       U+01D160 UTF-32 = ð (U+D834 U+DD60) UTF-16
    
    Imports System.IO
    
    Module Example4
        Public Sub Main()
            Dim sw As New StreamWriter(".\chars2.txt")
            Dim utf32 As Integer = &H1D160
            Dim surrogate As String = Char.ConvertFromUtf32(utf32)
            sw.WriteLine("U+{0:X6} UTF-32 = {1} ({2}) UTF-16",
                       utf32, surrogate, ShowCodePoints(surrogate))
            sw.Close()
        End Sub
    
        Private Function ShowCodePoints(value As String) As String
            Dim retval As String = Nothing
            For Each ch In value
                retval += String.Format("U+{0:X4} ", Convert.ToUInt16(ch))
            Next
            Return retval.Trim()
        End Function
    End Module
    ' The example produces the following output:
    '       U+01D160 UTF-32 = ð (U+D834 U+DD60) UTF-16
    

字符和字符类别

每个 Unicode 字符或有效的代理项对都属于 Unicode 类别。 在 .NET 中,Unicode 类别由枚举的成员 UnicodeCategory 表示,并包括值,例如 UnicodeCategory.CurrencySymbolUnicodeCategory.LowercaseLetter以及 UnicodeCategory.SpaceSeparator

若要确定字符的 Unicode 类别,请调用 GetUnicodeCategory 该方法。 例如,以下示例调用 GetUnicodeCategory 显示字符串中每个字符的 Unicode 类别。 仅当实例中 String 没有代理项对时,该示例才能正常工作。

using System;
using System.Globalization;

class Example
{
   public static void Main()
   {
      // Define a string with a variety of character categories.
      String s = "The red car drove down the long, narrow, secluded road.";
      // Determine the category of each character.
      foreach (var ch in s)
         Console.WriteLine("'{0}': {1}", ch, Char.GetUnicodeCategory(ch));
   }
}
// The example displays the following output:
//      'T': UppercaseLetter
//      'h': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'r': LowercaseLetter
//      'e': LowercaseLetter
//      'd': LowercaseLetter
//      ' ': SpaceSeparator
//      'c': LowercaseLetter
//      'a': LowercaseLetter
//      'r': LowercaseLetter
//      ' ': SpaceSeparator
//      'd': LowercaseLetter
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'v': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'd': LowercaseLetter
//      'o': LowercaseLetter
//      'w': LowercaseLetter
//      'n': LowercaseLetter
//      ' ': SpaceSeparator
//      't': LowercaseLetter
//      'h': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'l': LowercaseLetter
//      'o': LowercaseLetter
//      'n': LowercaseLetter
//      'g': LowercaseLetter
//      ',': OtherPunctuation
//      ' ': SpaceSeparator
//      'n': LowercaseLetter
//      'a': LowercaseLetter
//      'r': LowercaseLetter
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'w': LowercaseLetter
//      ',': OtherPunctuation
//      ' ': SpaceSeparator
//      's': LowercaseLetter
//      'e': LowercaseLetter
//      'c': LowercaseLetter
//      'l': LowercaseLetter
//      'u': LowercaseLetter
//      'd': LowercaseLetter
//      'e': LowercaseLetter
//      'd': LowercaseLetter
//      ' ': SpaceSeparator
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'a': LowercaseLetter
//      'd': LowercaseLetter
//      '.': OtherPunctuation
open System

// Define a string with a variety of character categories.
let s = "The red car drove down the long, narrow, secluded road."
// Determine the category of each character.
for ch in s do
    printfn $"'{ch}': {Char.GetUnicodeCategory ch}"

// The example displays the following output:
//      'T': UppercaseLetter
//      'h': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'r': LowercaseLetter
//      'e': LowercaseLetter
//      'd': LowercaseLetter
//      ' ': SpaceSeparator
//      'c': LowercaseLetter
//      'a': LowercaseLetter
//      'r': LowercaseLetter
//      ' ': SpaceSeparator
//      'd': LowercaseLetter
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'v': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'd': LowercaseLetter
//      'o': LowercaseLetter
//      'w': LowercaseLetter
//      'n': LowercaseLetter
//      ' ': SpaceSeparator
//      't': LowercaseLetter
//      'h': LowercaseLetter
//      'e': LowercaseLetter
//      ' ': SpaceSeparator
//      'l': LowercaseLetter
//      'o': LowercaseLetter
//      'n': LowercaseLetter
//      'g': LowercaseLetter
//      ',': OtherPunctuation
//      ' ': SpaceSeparator
//      'n': LowercaseLetter
//      'a': LowercaseLetter
//      'r': LowercaseLetter
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'w': LowercaseLetter
//      ',': OtherPunctuation
//      ' ': SpaceSeparator
//      's': LowercaseLetter
//      'e': LowercaseLetter
//      'c': LowercaseLetter
//      'l': LowercaseLetter
//      'u': LowercaseLetter
//      'd': LowercaseLetter
//      'e': LowercaseLetter
//      'd': LowercaseLetter
//      ' ': SpaceSeparator
//      'r': LowercaseLetter
//      'o': LowercaseLetter
//      'a': LowercaseLetter
//      'd': LowercaseLetter
//      '.': OtherPunctuation
Imports System.Globalization

Module Example1
    Public Sub Main()
        ' Define a string with a variety of character categories.
        Dim s As String = "The car drove down the narrow, secluded road."
        ' Determine the category of each character.
        For Each ch In s
            Console.WriteLine("'{0}': {1}", ch, Char.GetUnicodeCategory(ch))
        Next
    End Sub
End Module
' The example displays the following output:
'       'T': UppercaseLetter
'       'h': LowercaseLetter
'       'e': LowercaseLetter
'       ' ': SpaceSeparator
'       'r': LowercaseLetter
'       'e': LowercaseLetter
'       'd': LowercaseLetter
'       ' ': SpaceSeparator
'       'c': LowercaseLetter
'       'a': LowercaseLetter
'       'r': LowercaseLetter
'       ' ': SpaceSeparator
'       'd': LowercaseLetter
'       'r': LowercaseLetter
'       'o': LowercaseLetter
'       'v': LowercaseLetter
'       'e': LowercaseLetter
'       ' ': SpaceSeparator
'       'd': LowercaseLetter
'       'o': LowercaseLetter
'       'w': LowercaseLetter
'       'n': LowercaseLetter
'       ' ': SpaceSeparator
'       't': LowercaseLetter
'       'h': LowercaseLetter
'       'e': LowercaseLetter
'       ' ': SpaceSeparator
'       'l': LowercaseLetter
'       'o': LowercaseLetter
'       'n': LowercaseLetter
'       'g': LowercaseLetter
'       ',': OtherPunctuation
'       ' ': SpaceSeparator
'       'n': LowercaseLetter
'       'a': LowercaseLetter
'       'r': LowercaseLetter
'       'r': LowercaseLetter
'       'o': LowercaseLetter
'       'w': LowercaseLetter
'       ',': OtherPunctuation
'       ' ': SpaceSeparator
'       's': LowercaseLetter
'       'e': LowercaseLetter
'       'c': LowercaseLetter
'       'l': LowercaseLetter
'       'u': LowercaseLetter
'       'd': LowercaseLetter
'       'e': LowercaseLetter
'       'd': LowercaseLetter
'       ' ': SpaceSeparator
'       'r': LowercaseLetter
'       'o': LowercaseLetter
'       'a': LowercaseLetter
'       'd': LowercaseLetter
'       '.': OtherPunctuation

在内部,对于 ASCII 范围之外的字符(U+0000 到 U+00FF),该方法 GetUnicodeCategory 取决于类报告的 CharUnicodeInfo Unicode 类别。 从 .NET Framework 4.6.2 开始,Unicode 字符基于 Unicode 标准版本 8.0.0 进行分类。 在 .NET Framework 4 到 .NET Framework 4.6.1 的 .NET Framework 版本中,它们基于 Unicode 标准版本 6.3.0 进行分类。

字符和文本元素

由于单个字符可以由多个 Char 对象表示,因此处理单个 Char 对象并不总是有意义的。 例如,以下示例将表示爱琴海数字零到 9 的 Unicode 码位转换为 UTF-16 编码的代码单元。 因为它错误地将 Char 对象与字符相等,因此它不准确地报告生成的字符串有 20 个字符。

using System;

public class Example5
{
    public static void Main()
    {
        string result = String.Empty;
        for (int ctr = 0x10107; ctr <= 0x10110; ctr++)  // Range of Aegean numbers.
            result += Char.ConvertFromUtf32(ctr);

        Console.WriteLine("The string contains {0} characters.", result.Length);
    }
}
// The example displays the following output:
//     The string contains 20 characters.
open System

let result =
    [ for i in 0x10107..0x10110 do  // Range of Aegean numbers.
        Char.ConvertFromUtf32 i ]
    |> String.concat ""

printfn $"The string contains {result.Length} characters."


// The example displays the following output:
//     The string contains 20 characters.
Module Example5
    Public Sub Main()
        Dim result As String = String.Empty
        For ctr As Integer = &H10107 To &H10110     ' Range of Aegean numbers.
            result += Char.ConvertFromUtf32(ctr)
        Next
        Console.WriteLine("The string contains {0} characters.", result.Length)
    End Sub
End Module
' The example displays the following output:
'     The string contains 20 characters.

可以执行以下操作以避免假设对象 Char 表示单个字符:

  • 可以使用 String 整个对象,而不是使用其单个字符来表示和分析语言内容。

  • String.EnumerateRunes 以下示例所示:

    int CountLetters(string s)
    {
        int letterCount = 0;
    
        foreach (Rune rune in s.EnumerateRunes())
        {
            if (Rune.IsLetter(rune))
            { letterCount++; }
        }
    
        return letterCount;
    }
    
    let countLetters (s: string) =
        let mutable letterCount = 0
    
        for rune in s.EnumerateRunes() do
            if Rune.IsLetter rune then
                letterCount <- letterCount + 1
    
        letterCount
    
  • 可以使用 StringInfo 该类来处理文本元素,而不是单个 Char 对象。 以下示例使用 StringInfo 对象计算由爱琴海数字零到 9 组成的字符串中的文本元素数。 因为它认为代理项对是单个字符,所以它正确地报告该字符串包含 10 个字符。

    using System;
    using System.Globalization;
    
    public class Example4
    {
        public static void Main()
        {
            string result = String.Empty;
            for (int ctr = 0x10107; ctr <= 0x10110; ctr++)  // Range of Aegean numbers.
                result += Char.ConvertFromUtf32(ctr);
    
            StringInfo si = new StringInfo(result);
            Console.WriteLine("The string contains {0} characters.",
                              si.LengthInTextElements);
        }
    }
    // The example displays the following output:
    //       The string contains 10 characters.
    
    open System
    open System.Globalization
    
    let result =
        [ for i in 0x10107..0x10110 do  // Range of Aegean numbers.
            Char.ConvertFromUtf32 i ]
        |> String.concat ""
    
    
    let si = StringInfo result
    printfn $"The string contains {si.LengthInTextElements} characters."
    
    // The example displays the following output:
    //       The string contains 10 characters.
    
    Imports System.Globalization
    
    Module Example6
        Public Sub Main()
            Dim result As String = String.Empty
            For ctr As Integer = &H10107 To &H10110     ' Range of Aegean numbers.
                result += Char.ConvertFromUtf32(ctr)
            Next
            Dim si As New StringInfo(result)
            Console.WriteLine("The string contains {0} characters.", si.LengthInTextElements)
        End Sub
    End Module
    ' The example displays the following output:
    '       The string contains 10 characters.
    
  • 如果字符串包含具有一个或多个组合字符的基字符,则可以调用 String.Normalize 方法将子字符串转换为单个 UTF-16 编码的代码单元。 下面的示例调用 String.Normalize 该方法将基字符 U+0061(拉丁文 SMALL LETTER A)和组合字符 U+0308(COMBINING DIAERESIS)转换为 U+00E4(拉丁文小写字母 A WITH 分音)。

    using System;
    
    public class Example2
    {
        public static void Main()
        {
            string combining = "\u0061\u0308";
            ShowString(combining);
    
            string normalized = combining.Normalize();
            ShowString(normalized);
        }
    
        private static void ShowString(string s)
        {
            Console.Write("Length of string: {0} (", s.Length);
            for (int ctr = 0; ctr < s.Length; ctr++)
            {
                Console.Write("U+{0:X4}", Convert.ToUInt16(s[ctr]));
                if (ctr != s.Length - 1) Console.Write(" ");
            }
            Console.WriteLine(")\n");
        }
    }
    // The example displays the following output:
    //       Length of string: 2 (U+0061 U+0308)
    //
    //       Length of string: 1 (U+00E4)
    
    open System
    
    let showString (s: string) =
        printf $"Length of string: {s.Length} ("
        for i = 0 to s.Length - 1 do
            printf $"U+{Convert.ToUInt16 s[i]:X4}"
            if i <> s.Length - 1 then printf " "
        printfn ")\n"
    
    let combining = "\u0061\u0308"
    showString combining
    
    let normalized = combining.Normalize()
    showString normalized
    
    // The example displays the following output:
    //       Length of string: 2 (U+0061 U+0308)
    //
    //       Length of string: 1 (U+00E4)
    
    Module Example3
        Public Sub Main()
            Dim combining As String = ChrW(&H61) + ChrW(&H308)
            ShowString(combining)
    
            Dim normalized As String = combining.Normalize()
            ShowString(normalized)
        End Sub
    
        Private Sub ShowString(s As String)
            Console.Write("Length of string: {0} (", s.Length)
            For ctr As Integer = 0 To s.Length - 1
                Console.Write("U+{0:X4}", Convert.ToUInt16(s(ctr)))
                If ctr <> s.Length - 1 Then Console.Write(" ")
            Next
            Console.WriteLine(")")
            Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Length of string: 2 (U+0061 U+0308)
    '       
    '       Length of string: 1 (U+00E4)
    

常见操作

Char 结构提供比较 Char 对象的方法,将当前 Char 对象的值转换为另一种类型的对象,并确定对象的 Unicode 类别 Char

要执行此操作 使用这些 System.Char 方法
比较 Char 对象 CompareToEquals
将代码点转换为字符串 ConvertFromUtf32

另请参阅类型 Rune
Char 对象或代理项对 Char 转换为代码点 对于单个字符: Convert.ToInt32(Char)

对于代理项对或字符串中的字符: Char.ConvertToUtf32

另请参阅类型 Rune
获取字符的 Unicode 类别 GetUnicodeCategory

另请参阅 Rune.GetUnicodeCategory
确定字符是否位于特定的 Unicode 类别中,例如数字、字母、标点符号、控制字符等 IsControlIsDigit、、IsLetterIsHighSurrogate、、 IsLowerIsLetterOrDigitIsUpperIsSymbolIsSurrogateIsPunctuationIsSurrogatePairIsLowSurrogateIsNumberIsSeparatorIsWhiteSpace

另请参阅有关 Rune 该类型的相应方法。
Char 表示数字的对象转换为数值类型 GetNumericValue

另请参阅 Rune.GetNumericValue
将字符串中的字符转换为 Char 对象 ParseTryParse
Char 对象转换为 String 对象 ToString
更改对象的大小写Char ToLowerToLowerInvariantToUpperToUpperInvariant

另请参阅有关 Rune 该类型的相应方法。

字符值和互操作

当托管 Char 类型(表示为 Unicode UTF-16 编码的代码单元)传递到非托管代码时,互操作封送器默认将字符集转换为 ANSI。 可以将属性 DllImportAttribute 应用于平台调用声明,并将 StructLayoutAttribute 属性应用于 COM 互操作声明,以控制封送 Char 类型使用的字符集。