探究 C# 中的 char 、 string(一)
目錄- 探究 C# 中的 char 、 string(一)
- 1. System.Char 字符
- 2. 字符處理
- 3. 全球化
- 4. System.String 字串
- 4.1 字串搜索
- 4.2 字串提取、插入、洗掉、替換
- 4.2.1 提取
- 4.2.2 插入、洗掉、替換
- 5. 字串駐留池
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 可以隱式轉為其他數值型別,整型有可以轉為ushort,int,uint,long,和ulong,浮點型 可以轉為 float,double,和decimal,
char 可以顯式轉為 sbyte,byte和short,
其他型別無法隱式轉為 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 有很豐富的方法去處理字符,例如常用的 ToUpper、ToLower ,
但是字符的處理,會受到用戶語言環境的影響,
使用 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# 字串的使用和駐留池等原理,請參考
http://community.bartdesmet.net/blogs/bart/archive/2006/09/27/4472.aspx
通過設法在程式集中獲取字串文字的串列
https://stackoverflow.com/questions/22172175/read-the-content-of-the-string-intern-pool
.NET 底層 Profiling API說明
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/profiling-overview?redirectedfrom=MSDN
.NET字串駐留池和提高字串比較性能
http://benhall.io/net-string-interning-to-improve-performance/
關于 C# 字串駐留池的學習文章
https://www.cnblogs.com/mingxuantongxue/p/3782391.html
https://www.xuebuyuan.com/189297.html
https://www.xuebuyuan.com/189297.html
如果總結或知識有錯,麻煩大佬們斧正哈,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/98000.html
標籤:C#
