C#中的char与string详解

1. System.Char 字符

char 是 System.Char 的别名。

System.Char 占两个字节,16个二进制位。

System.Char 用来表示、存储一个 Unicode 字符。

System.Char 的表示范围是 U+0000 到U+FFFF,char 默认值是 \0,即 U+0000

Unicode 的表示,通常以 U+____形式表示,即 U 和 一组16进制的数字组成。

char 有四种赋值方法

            char a = 'j';
            char b = '\u006A';
            char c = '\x006A';
            char d = (char) 106;
            Console.WriteLine($"{a} | {b} | {c} | {d}");

输出

j | j | j | j

\u 开头是 Unicode 转义序列(编码);使用 Unicode 转义序列,后面必须是4个十六进制的数字。

\u006A    有效
\u06A	  无效
\u6A	  无效

\x 开头是 十六进制转义序列,也是由4个十六进制数字组成。如果前面是N个0的话,则可以省略0。下面的示例都是表示同一个字符。

\x006A
\x06A
\x6A

char 可以隐式转为其他数值类型,整型有可以转为ushortintuintlong,和ulong,浮点型 可以转为 floatdouble,和decimal

char 可以显式转为 sbytebyteshort

其他类型无法隐式转为 char 类型,但是任何整型和浮点型都可以显式转为 char。

2. 字符处理

System.Char 中,具有很多就态方法,能够有助于识别、处理字符。

有一个非常重要的 UnicodeCategory 枚举

  public enum UnicodeCategory
  {
    UppercaseLetter,
    LowercaseLetter,
    TitlecaseLetter,
    ModifierLetter,
    OtherLetter,
    NonSpacingMark,
    SpacingCombiningMark,
    EnclosingMark,
    DecimalDigitNumber,
    LetterNumber,
    OtherNumber,
    SpaceSeparator,
    LineSeparator,
    ParagraphSeparator,
    Control,
    Format,
    Surrogate,
    PrivateUse,
    ConnectorPunctuation,
    DashPunctuation,
    OpenPunctuation,
    ClosePunctuation,
    InitialQuotePunctuation,
    FinalQuotePunctuation,
    OtherPunctuation,
    MathSymbol,
    CurrencySymbol,
    ModifierSymbol,
    OtherSymbol,
    OtherNotAssigned,
  }

System.Char 中, 有一个 GetUnicodeCategory() 静态方法,可以返回字符的类型,即上面的枚举值。

除了 GetUnicodeCategory() ,我们还可以通过具体的静态方法判断字符的类别。

下面列出静态方法的使用说明的枚举类别。

静态方法 说明 枚举表示
IsControl 值小于0x20 的不可打印字符。例如 \r、\n、\t、\0等。
IsDigit 0-9和其他字母表中的数字 DecimalDigitNumber
IsLetter A-Z、a-z 和其他字母字符 UppercaseLetter,
LowercaseLetter,
TitlecaseLetter,
ModifierLetter,
OtherLetter
IsLetterOrDigit 字母和数字 参考 IsLetter 和 IsDigit
IsLower 小写字母 LowercaseLetter
IsNumber 数字、Unicode中的分数、罗马数字 DecimalDigitNumber,
LetterNumber,
OtherNumber
IsPunctuation 西方和其他字母表中的标点符号 ConnectorPunctuation,
DashPunctuation,
InitialQuotePunctuation,
FinalQuotePunctuation,
OtherPunctuation
IsSeparator 空格和所有的 Unicode 分隔符 SpaceSeparator,
ParagraphSeparator
IsSurrogate 0x10000到0x10FFF之间的Unicode值 Surrogate
IsSymbol 大部分可打印字符 MathSymbol,
ModifierSymbol,
OtherSymbol
IsUpper 大小字母 UppercaseLetter
IsWhiteSpace 所有的分隔符以及 \t、\n、\r、\v、\f SpaceSeparator,
ParagraphSeparator

示例

        char chA = 'A';
        char ch1 = '1';
        string str = "test string"; 

        Console.WriteLine(chA.CompareTo('B'));          //-----------  Output: "-1
														//(meaning 'A' is 1 less than 'B')
        Console.WriteLine(chA.Equals('A'));             //-----------  Output: "True"
        Console.WriteLine(Char.GetNumericValue(ch1));   //-----------  Output: "1"
        Console.WriteLine(Char.IsControl('\t'));        //-----------  Output: "True"
        Console.WriteLine(Char.IsDigit(ch1));           //-----------  Output: "True"
        Console.WriteLine(Char.IsLetter(','));          //-----------  Output: "False"
        Console.WriteLine(Char.IsLower('u'));           //-----------  Output: "True"
        Console.WriteLine(Char.IsNumber(ch1));          //-----------  Output: "True"
        Console.WriteLine(Char.IsPunctuation('.'));     //-----------  Output: "True"
        Console.WriteLine(Char.IsSeparator(str, 4));    //-----------  Output: "True"
        Console.WriteLine(Char.IsSymbol('+'));          //-----------  Output: "True"
        Console.WriteLine(Char.IsWhiteSpace(str, 4));   //-----------  Output: "True"
        Console.WriteLine(Char.Parse("S"));             //-----------  Output: "S"
        Console.WriteLine(Char.ToLower('M'));           //-----------  Output: "m"
        Console.WriteLine('x'.ToString());              //-----------  Output: "x"
        Console.WriteLine(Char.IsSurrogate('\U00010F00'));		// Output: "False"
        char test = '\xDFFF';
        Console.WriteLine(test);						//-----------	Output:'?'
        Console.WriteLine( Char.GetUnicodeCategory(test));//-----------	Output:"Surrogate"

如果想满足你的好奇心,可以点击 http://www1.cs.columbia.edu/~lok/csharp/refdocs/System/types/Char.html

3. 全球化

C# 中 System.Char 有很丰富的方法去处理字符,例如常用的 ToUpperToLower 。

但是字符的处理,会受到用户语言环境的影响。

使用 System.Char 中的方法处理字符时,可以调用带有 Invariant 后缀的方法或使用 CultureInfo.InvariantCulture,以进行与语言环境无关的字符处理。

示例

            Console.WriteLine(Char.ToUpper('i',CultureInfo.InvariantCulture));
            Console.WriteLine(Char.ToUpperInvariant('i'));

对于字符和字符串处理,可能用到的重载参数和处理方式,请看下面的说明。

StringComparison

枚举 枚举值 说明
CurrentCulture 0 使用区分文化的排序规则和当前区域性来比较字符串
CurrentCultureIgnoreCase 1 使用对区域性敏感的排序规则,当前区域性来比较字符串,而忽略要比较的字符串的大小写
InvariantCulture 2 使用区分文化的排序规则和不变区域性比较字符串
InvariantCultureIgnoreCase 3 使用区分区域性的排序规则,不变区域性来比较字符串,而忽略要比较的字符串的大小写
Ordinal 4 使用序数(二进制)排序规则比较字符串
OrdinalIgnoreCase 5 使用序数(二进制)排序规则比较字符串,而忽略要比较的字符串的大小写

CultureInfo

枚举 说明
CurrentCulture 获取表示当前线程使用的区域性的 CultureInfo对象
CurrentUICulture 获取或设置 CultureInfo对象,该对象表示资源管理器在运行时查找区域性特定资源时所用的当前用户接口区域性
InstalledUICulture 获取表示操作系统中安装的区域性的 CultureInfo
InvariantCulture 获取不依赖于区域性(固定)的 CultureInfo 对象
IsNeutralCulture 获取一个值,该值指示当前 CultureInfo 是否表示非特定区域性

4. System.String 字符串

4.1 字符串搜索

字符串有多个搜索方法:StartsWith()EndsWith()Contains()IndexOf

StartsWith() 和 EndsWith() 可以使用 StringComparison 比较方式、CultureInfo 控制文化相关规则。

StartsWith() :字符串开头是否存在符合区配字符串

EndsWith(): 字符串结尾是否存在符合区配字符串

Contains(): 字符串任意位置是否存在区配字符串

IndexOf: 字符串或字符首次出现的索引位置,如果返回值为 -1 则表示无区配结果。

使用示例

            string a = "痴者工良(高级程序员劝退师)";
            Console.WriteLine(a.StartsWith("高级"));
            Console.WriteLine(a.StartsWith("高级",StringComparison.CurrentCulture));
            Console.WriteLine(a.StartsWith("高级",true, CultureInfo.CurrentCulture));
            Console.WriteLine(a.StartsWith("痴者",StringComparison.CurrentCulture));
            Console.WriteLine(a.EndsWith("劝退师)",true, CultureInfo.CurrentCulture));
            Console.WriteLine(a.IndexOf("高级",StringComparison.CurrentCulture));

输出

False
False
False
True
True
5

除了 Contains(),其它三种方法都有多个重载方法,例如

重载 说明
(String) 是否与指定字符串区配
(String, StringComparison) 以何种方式指定字符串区配
(String, Boolean, CultureInfo) 控制大小写和文化规则指定字符串区配

这些与全球化和大小写区配的规则,在后面章节中会说到。

4.2 字符串提取、插入、删除、替换

4.2.1 提取

SubString() 方法可以在提取字符串指定索开始的N个长度或余下的所有的字符。

            string a = "痴者工良(高级程序员劝退师)";
            string a = "痴者工良(高级程序员劝退师)";
            Console.WriteLine(a.Substring(startIndex: 1, length: 3));
            // 者工良
            Console.WriteLine(a.Substring(startIndex: 5));
            // 高级程序员劝退师)

4.2.2 插入、删除、替换

Insert() :指定索引位置后插入字符或字符串

Remove() :指定索引位置后插入字符或字符串

PadLeft() :在字符串左侧将使用某个字符串扩展到N个字符长度

PadRight():在字符串右侧将使用某个字符串扩展到N个字符长度

TrimStart() :从字符串左侧开始删除某个字符,碰到不符合条件的字符即停止。

TrimEnd() :从字符串右侧开始删除某个字符,碰到不符合条件的字符即停止。

Replace():将字符串中的N连续个字符组替换为新的M个字符组。

示例

            string a = "痴者工良(高级程序员劝退师)"; // length = 14

            Console.WriteLine("\n  -  Remove Insert   - \n");

            Console.WriteLine(a.Insert(startIndex: 4, value: "我是"));
            Console.WriteLine(a.Remove(startIndex: 5));
            Console.WriteLine(a.Remove(startIndex: 5, count: 3));

            Console.WriteLine("\n  -  PadLeft PadRight  -  \n");

            Console.WriteLine(a.PadLeft(totalWidth: 20, paddingChar: '*'));
            Console.WriteLine(a.PadRight(totalWidth: 20, paddingChar: '#'));
            Console.WriteLine(a.PadLeft(totalWidth: 20, paddingChar: '\u0023'));
            Console.WriteLine(a.PadRight(totalWidth: 20, paddingChar: '\u002a'));
            Console.WriteLine(a.PadLeft(totalWidth: 18, paddingChar: '.'));
            Console.WriteLine(a.PadRight(totalWidth: 18, paddingChar: '.'));

            Console.WriteLine("\n  -  Trim  -  \n");

            Console.WriteLine("|Hello | World|".Trim('|'));
            Console.WriteLine("|||Hello | World|||".Trim('|'));
            Console.WriteLine("|Hello | World!|".TrimStart('|'));
            Console.WriteLine("|||Hello | World!|||".TrimStart('|'));
            Console.WriteLine("|Hello | World!|".TrimEnd('|'));
            Console.WriteLine("|||Hello | World!|||".TrimEnd('|'));
            Console.WriteLine("||||||||||||||||||||||||".TrimEnd('|'));

            Console.WriteLine("*#&abc ABC&#*".TrimStart(new char[] {'*', '#', '&'}));
            Console.WriteLine("*#&abc ABC&#*".TrimStart(new char[] {'#', '*', '&'}));

            Console.WriteLine("\n  -  Replace  -  \n");

            Console.WriteLine("abcdABCDabcdABCD".Replace(oldChar: 'a', newChar: 'A'));

输出

  -  Remove Insert   -

痴者工良我是(高级程序员劝退师)
痴者工良(
痴者工良(序员劝退师)

  -  PadLeft PadRight  -

******痴者工良(高级程序员劝退师)
痴者工良(高级程序员劝退师)######
######痴者工良(高级程序员劝退师)
痴者工良(高级程序员劝退师)******
....痴者工良(高级程序员劝退师)
痴者工良(高级程序员劝退师)....

  -  Trim  -

Hello | World
Hello | World
Hello | World!|
Hello | World!|||
|Hello | World!
|||Hello | World!

abc ABC&#*
abc ABC&#*

  -  Replace  -

AbcdABCDAbcdABCD

5. 字符串驻留池

以下为笔者个人总结,限于水平,如若有错,望各位加以批评指正。

字符串 驻留池是在域(Domain)级别完成的,而字符串驻留池可以在域中的所有程序集之间共享。

CLR 中维护着一个叫做驻留池(Intern Pool)的表。

这个表记录了所有在代码中使用字面量声明的字符串实例的引用。

拼接方式操作字面量时,新的字符串又会进入字符串驻留池。

只有使用使用字面量声明的字符串实例,实例才会对字符串驻留池字符串引用。

而无论是字段属性或者是方法内是声明的 string 变量、甚至是方法参数的默认值,都会进入字符串驻留池。

例如

        static string test = "一个测试";

        static void Main(string[] args)
        {
            string a = "a";

            Console.WriteLine("test:" + test.GetHashCode());

            TestOne(test);
            TestTwo(test);
            TestThree("一个测试");
        }

        public static void TestOne(string a)
        {
            Console.WriteLine("----TestOne-----");
            Console.WriteLine("a:" + a.GetHashCode());
            string b = a;
            Console.WriteLine("b:" + b.GetHashCode());
            Console.WriteLine("test - a :" + Object.ReferenceEquals(test, a));
        }

        public static void TestTwo(string a = "一个测试")
        {
            Console.WriteLine("----TestTwo-----");
            Console.WriteLine("a:" + a.GetHashCode());
            string b = a;
            Console.WriteLine("b:" + b.GetHashCode());
            Console.WriteLine("test - a :" + Object.ReferenceEquals(test, a));
        }

        public static void TestThree(string a)
        {
            Console.WriteLine("----TestThree-----");
            Console.WriteLine("a:" + a.GetHashCode());
            string b = a;
            Console.WriteLine("b:" + b.GetHashCode());
            Console.WriteLine("test - a :" + Object.ReferenceEquals(test, a));
        }

输出结果

test:-407145577
----TestOne-----
a:-407145577
b:-407145577
test - a :True
----TestTwo-----
a:-407145577
b:-407145577
test - a :True
----TestThree-----
a:-407145577
b:-407145577
test - a :True

可以通过静态方法 Object.ReferenceEquals(s1, s2); 或者 实例的 .GetHashCode() 来对比两个字符串是否为同一个引用。

可以使用不安全代码,直接修改内存中的字符串

参考 https://blog.benoitblanchon.fr/modify-intern-pool/

string a = "Test";

fixed (char* p = a)
{
    p[1] = '3';
}

Console.WriteLine(a);

使用 *Microsoft.Diagnostics.Runtime* 可以获取 CLR 的信息。

结果笔者查阅大量资料发现,.NET 不提供 API 去查看字符串常量池里面的哈希表。

到此这篇关于C#中的char与string详解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • c# StringBuilder.Replace 方法 (Char, Char, Int32, Int32)

    将此实例的子字符串中所有指定字符的匹配项替换为其他指定字符. 命名空间:System.Text  程序集:mscorlib(在 mscorlib.dll 中) 语法  C#  public StringBuilder Replace (  char oldChar,  char newChar,  int startIndex,  int count  )  参数  oldChar  要替换的字符. newChar  替换 oldChar 的字符. startIndex  此实例中子字符串开始的

  • C# char[]与string byte[]与string之间的转换详解

    1.char[]与string之间的转换 //string 转换成 Char[] string str="hello"; char[] arr=str.ToCharArray(); //Char[] 转换成 string string str1 = new string(arr); 2.byte[]与string之间的转化 string str = "你好,hello"; byte[] bytes; //byte[] 转换成 string bytes = Encod

  • C#中的char、string和StringBuilder的使用详解

    char 字符 char代表一个Unicode字符,它是System.Char的别名 char someChar = 'a';//定义了一个字符 char newLine= '\n';//这是一个换行符 System.Char定义了一组静态方法: ToUpper 将指定的字符转换为等效的大写形式 ToLower 将指定的字符转换为等效的小写形式 IsWhiteSpace 判断指定的字符是否为空白字符 -- 例子: Console.WriteLine(char.ToUpper('c'));//输出

  • C#中char和string的入门使用教程

    char 字符 char代表一个Unicode字符,它是System.Char的别名 char someChar = 'a';//定义了一个字符 char newLine= '\n';//这是一个换行符 System.Char定义了一组静态方法: ToUpper 将指定的字符转换为等效的大写形式 ToLower 将指定的字符转换为等效的小写形式 IsWhiteSpace 判断指定的字符是否为空白字符 -- 例子: Console.WriteLine(char.ToUpper('c'));//输出

  • C#中的char与string详解

    1. System.Char 字符 char 是 System.Char 的别名. System.Char 占两个字节,16个二进制位. System.Char 用来表示.存储一个 Unicode 字符. System.Char 的表示范围是 U+0000 到U+FFFF,char 默认值是 \0,即 U+0000. Unicode 的表示,通常以 U+____形式表示,即 U 和 一组16进制的数字组成. char 有四种赋值方法 char a = 'j'; char b = '\u006A'

  • JDBC中resutset接口操作实例详解

    本文主要向大家展示JDBC接口中resutset接口的用法实例,下面我们看看具体内容. 1. ResultSet细节1 功能:封锁结果集数据 操作:如何获得(取出)结果 package com.sjx.a; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import org.junit.Test; //1. next方

  • C++中Socket网络编程实例详解

    C++中Socket网络编程实例详解 现在几乎所有C/C++的后台程序都需要进行网络通讯,其实现方法无非有两种:使用系统底层socket或者使用已有的封装好的网络库.本文对两种方式进行总结,并介绍一个轻量级的网络通讯库ZeroMQ.  1.基本的Scoket编程 关于基本的scoket编程网络上已有很多资料,作者在这里引用一篇文章中的内容进行简要说明. 基于socket编程,基本上就是以下6个步骤: 1.socket()函数 2.bind()函数 3.listen().connect()函数 4

  • JavaScript 中调用 Kotlin 方法实例详解

    JavaScript 中调用 Kotlin 方法实例详解 Kotlin 编译器生成正常的 JavaScript 类,可以在 JavaScript 代码中自由地使用的函数和属性 .不过,你应该记住一些微妙的事情. 用独立的 JavaScript 隔离声明 为了防止损坏全局对象,Kotlin 创建一个包含当前模块中所有 Kotlin 声明的对象 .所以如果你把模块命名为 myModule,那么所有的声明都可以通过 myModule 对象在 JavaScript 中可用.例如: fun foo() =

  • java 中file.encoding的设置详解

    java 中file.encoding的设置详解 昨天有人在讨论关于设置System的property,file.encoding 修改defaultcharset无效 Properties pps=System.getProperties(); pps.setProperty("file.encoding","ISO-8859-1"); 在java中,如果没有指定charset的时候,比如new String(byte[] bytes),都会调用Charset.d

  • java中switch选择语句代码详解

    switch结构(开关语句)的语法 switch(表达式 ){ --->类型为int.char case 常量1 :--->case 结构可以有多个 //语句块1 break; --->程序跳出switch结构 case 常量n :--->常量的值不能相同 //语句块n break; default:--->和if结构中的 else作用相同 //语句块 break; } 下面看一段代码示例,有详细的注释,大家可以参考: public class SwitchStu{ /* s

  • C语言中的正则表达式使用示例详解

    正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE).正则表达式是使用单个字符串来描述.匹配一系列符合某个句法规则的字符串. 在c语言中,用regcomp.regexec.regfree 和regerror处理正则表达式.处理正则表达式分三步: 编译正则表达式,regcomp: 匹配正则表达式,regexec: 释放正则表达式,regfree. 函数原型 /* 函数说明:Regcomp将正则表达式字符串regex编译

  • MyBatis中的JdbcType映射使用详解

    Java项目涉及到数据库交互,以往常用的是JDBC,现在则有Hibernate.Mybatis等这些持久化支持. 项目中用到了MyBatis,和JDBC最显著的区别,就是SQL语句配置化,通过xml文件定义SQL语句,当然JDBC也可以将SQL配置化,需要定制开发,MyBatis则直接支持这种方法. 官方对于MyBatis的介绍, MyBatis is a first class persistence framework with support for custom SQL, stored

  • C++中static修饰符的详解及其作用介绍

    目录 概述 静态数据成员 引用静态数据成员 用类名访问数据成员 静态成员函数 综合案例 概述 static (静态) 修饰符是用来控制变量的存储方式和可见性的. 静态局部变量存储在静态区域: static 的性质: 局部特性:作用范围仅限于本函数 静态特性:存储在静态区, 函数调用结束后不孝顺而保留原值. 在下一次调用时, 保留上一次调用结束时的值. 静态数据成员 在我们定义全局变量的时候, 我们会发现一个问题: 我们可以在程序各处自由的修改全局变量的值 (不安全). 静态数据成员的特点: 静态

随机推荐