服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#中的char与string详解

C#中的char与string详解

2022-12-21 14:14痴者工良 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 有四种赋值方法

?
1
2
3
4
5
char a = 'j';
char b = '\u006A';
char c = '\x006A';
char d = (char) 106;
Console.WriteLine($"{a} | {b} | {c} | {d}");

输出

?
1
j | j | j | j

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

?
1
2
3
\u006A    有效
\u06A     无效
\u6A      无效

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

?
1
2
3
\x006A
\x06A
\x6A

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

char 可以显式转为 sbytebyteshort

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

2. 字符处理

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

有一个非常重要的 UnicodeCategory 枚举

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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,以进行与语言环境无关的字符处理。

示例

?
1
2
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 则表示无区配结果。

使用示例

?
1
2
3
4
5
6
7
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));

输出

?
1
2
3
4
5
6
False
False
False
True
True
5

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

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

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

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

4.2.1 提取

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

?
1
2
3
4
5
6
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个字符组。

示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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'));

输出

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  -  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 变量、甚至是方法参数的默认值,都会进入字符串驻留池。

例如

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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));
}

输出结果

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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/

?
1
2
3
4
5
6
7
8
string a = "Test";
 
fixed (char* p = a)
{
    p[1] = '3';
}
 
Console.WriteLine(a);

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

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

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

原文链接:https://www.cnblogs.com/whuanle/p/11967014.html

延伸 · 阅读

精彩推荐
  • C#C# 对Outlook2010进行二次开发的图文教程

    C# 对Outlook2010进行二次开发的图文教程

    下面小编就为大家分享一篇C# 对Outlook2010进行二次开发的图文教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    久久小垠5692022-02-16
  • C#C#实现将窗体固定在显示器的左上角且不能移动的方法

    C#实现将窗体固定在显示器的左上角且不能移动的方法

    这篇文章主要介绍了C#实现将窗体固定在显示器的左上角且不能移动的方法,涉及C#窗体固定操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    我心依旧6372021-10-21
  • C#详解C#中的泛型以及编程中使用泛型的优点

    详解C#中的泛型以及编程中使用泛型的优点

    这篇文章主要介绍了详解C#中的泛型以及编程中使用泛型的优点,对泛型的支持时C#语言中的重要特性,需要的朋友可以参考下...

    C#教程网4572021-11-11
  • C#C#实现SQL批量插入数据到表的方法

    C#实现SQL批量插入数据到表的方法

    这篇文章主要介绍了C#实现SQL批量插入数据到表的方法,涉及C#批量操作SQL的相关技巧,需要的朋友可以参考下...

    且行且思4102021-11-18
  • C#C#笔试题之同线程Lock语句递归不会死锁

    C#笔试题之同线程Lock语句递归不会死锁

    这篇文章主要介绍了C#笔试题之同线程Lock语句递归不会死锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    森大科技10782022-08-27
  • C#利用C#操作WMI指南

    利用C#操作WMI指南

    WMI提供了一套内置在Microsoft Windows操作系统中的丰富的系统管理服务,可以在有大量的应用程序、服务和设备的系统中提供全方位的管理功能。它允许应用...

    C#教程网12092021-12-10
  • C#C#实现获取IIS站点及虚拟目录信息的方法

    C#实现获取IIS站点及虚拟目录信息的方法

    这篇文章主要介绍了C#实现获取IIS站点及虚拟目录信息的方法,可实现获取IIS站点信息及物理路径等功能,具有一定参考借鉴价值,需要的朋友可以参考下...

    蓝图12302021-10-28
  • C#c# 基于Titanium爬取微信公众号历史文章列表

    c# 基于Titanium爬取微信公众号历史文章列表

    这篇文章主要介绍了c# 基于Titanium爬取微信公众号历史文章列表,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下...

    leestar546572022-11-07