C# 数据类型之 String(字符串)

Ø  简介

在开发中最常见的数据类型就是 String 类型,即字符串类型。为什么要单独讨论下这个类型,是因为:它是系统内置的基础数据类型;它的使用频率非常高;它是一个特殊的引用类型。其实大家都会使用它,但可能或多或少了解不够全面,本文主要是抱着:学习、巩固、总结的目的去加深对它的了解,主要学习以下几点:

1.   什么是 string 类型

2.   创建 string 对象的方式

3.   string 的常用静态方法

4.   string 的常用实例方法

5.   string 的常用扩展方法

6.   string 的使用技巧

7.   char 的常用静态方法

 

1.   什么是 string 类型

1)   它主要用于存储一组连续字符(char),一个完整的字符串对象可以看作是一个 char 类型的数组,既然是数组我们就可以把它当作集合去使用,例如:

string str1 = "abc";

char[] chars = new char[str1.Length];

//方式1

for (int i = 0; i < chars.Length; i++)

    chars[i] = str1[i];

//方式2

chars = str1.ToArray();

 

2)   它是一种特殊的引用类型

1.   MSDN 上,string 就被分为引用类型,https://msdn.microsoft.com/zh-cn/library/t63sy5hs(VS.80).aspx

另外,从声明上也可以看出,它是一个密封的 class

public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>

注:可见,string 实现了 IEnumerable<char> 接口,所以 string 也可以使用很多 IEnumerable<char> 接口的扩展方法。

 

2.   string 的值具有不变性

string 最显著的特点就是它具有恒定不变性,我们一旦创建了一个 string 对象,就不能以任何方式改变该对象的值,比如:追加、删减、改变格式等。有时看上去改变了某个字符串,但实际上则是创建了一个新的字符串实例。

 

3.   为什么又说它是一种特殊的引用类型呢,是因为它是引用类型,有时却表现出值类型的特点,例如:

1)   示例一

string str2 = "abc";

string str3 = str2;

str2 = "def";

Console.WriteLine("str2:{0}, str3:{1}", str2, str3);    //str2def, str3abc

首先,将"abc"存储在内存中,并将引用地址赋给 str2;然后,将 str2 的引用赋给 str3,此时 str2 str3 具有相同的引用;最后,改变了 str2 的值(注意是新值并不是改变),此时 str2 str3 并不是引用同一个内存地址。所以,最终输出并不相同。(个人理解)

clip_image001

 

2)   示例二(以上示例解释通了,下面的示例又做如何解释)

StringTestOne stringTestOne1 = new StringTestOne() { Name = "爱变成" };

StringTestOne stringTestOne2 = stringTestOne1;

stringTestOne2.Name = "张无忌";

Console.WriteLine("One1.Name:{0}, One2.Name:{1}", stringTestOne1.Name, stringTestOne2.Name);    //One1.Name:张无忌, One2.Name:张无忌

首先,创建了一个包含 Name 属性的对象;然后,将该对象的引用赋值给 stringTestOne2;之后,再改变了 stringTestOne2.Name 的值;结果,输出两个对象的 Name 属性,尽然是一样的值。

这样是不是有点蒙了,为什么跟上面的示例不太一样呢?我们先看引用情况:

bool bool1_1 = object.ReferenceEquals(stringTestOne1, stringTestOne2);              //true

bool bool1_2 = object.ReferenceEquals(stringTestOne1.Name, stringTestOne2.Name);    //true

没错,它们是相同的对象引用,无论是对象还是属性,都是同一个引用地址。

至此,再画张图解释一下:

clip_image003

讨论:http://social.msdn.microsoft.com/Forums/zh-CN/visualcshartzhchs/thread/ce580186-86d9-45f7-b5ff-20302caf1324

 

2.   创建 string 对象的方式

1)   直接赋值

string str5 = "abc";    //在堆中创建对象,并将引用分配给变量 str5

2)   调用 string 的构造函数(+ 7 重载)

string str6 = new string(new char[] { 'a', 'b', 'c' });

 

3.   string 的常用静态方法

1)   Compare() 方法+ 10 重载,比较两个字符串。示例:

int int1 = string.Compare("acd", "abc");  //1

int int2 = string.Compare("123", "135");  //-1

int int3 = string.Compare("", "");    //0

 

2)   Concat() 方法+ 10 重载,连接(串联)每个参数示例:

string str7 = string.Concat("abc", true, 3);    //abcTrue3

 

3)   Join () 方法+ 4 重载,使用指定的分隔符,连接(串联)每个参数示例:

string str8 = string.Join(",", new int[] { 1, 2, 3 });  //1,2,3

string str8_1 = string.Join(",", new int[] { 1 });      //1

string str8_2 = string.Join(",", new int[] { });        //""

string str8_3 = string.Join(",", null);                 //System.ArgumentNullException:值不能为 null

 

4)   Copy() 方法,将指定的字符串的值拷贝到新的字符串。示例:

string str9 = "abc123";             //abc123

string str10 = str9;                //abc123

string str11 = string.Copy(str9);   //abc123

bool bool1 = str9.Equals(str10);    //true

bool bool2 = str9.Equals(str11);    //true

bool bool3 = object.ReferenceEquals(str9, str10);   //true

bool bool4 = object.ReferenceEquals(str9, str11);   //false

注:可见,使用 Copy() 方法拷贝值的方式,与原对象的引用不同。

 

5)   Equals() 方法+ 2 重载,比较两个字符串的值是否相等。示例:

string str12 = "abc123";

string str13 = "abc123";

bool bool5 = string.Equals(str12, str13);           //true

bool bool6 = object.ReferenceEquals(str12, str13);  //true

bool bool6_1 = string.Equals("a", "A", StringComparison.CurrentCulture);            //false

bool bool6_2 = string.Equals("a", "A", StringComparison.CurrentCultureIgnoreCase);  //true

注:可见,相同值的字符串对象并不会重复创建,这个很关键!

 

6)   Format() 方法(+ 4 重载),根据指定的格式格式化字符串。示例:

string str14 = string.Format("格式化{0}", "字符串");      //格式化字符串

//输出字符串包含“{”时,需要使用"{{"转义

string str15 = string.Format("{{格式化{0}", "字符串");    //{格式化字符串

//string str16_1 = string.Format("{0}{1}", "a");    //System.FormatException:索引(从零开始)必须大于或等于零,且小于参数列表的大小。

string str16_2 = string.Format("{0}{1}", "a", "b", "c");    //ab(注:可见,参数列表可多不可少,多余的则忽略。)

 

1.   去除小数点后面无效的零

string str16_3 = string.Format("{0:0.##}", 16.00m);     //16

string str16_4 = string.Format("{0:0.##}", 16.10m);     //16.1

string str16_5 = string.Format("{0:0.##}", 16.06m);     //16.06

string str16_6 = string.Format("{0:0.##}", 16.160m);    //16.16

string str16_7 = string.Format("{0:0.##}", 16.164m);    //16.16

string str16_8 = string.Format("{0:0.##}", 16.165m);    //16.17(注:进行了四舍五入)

 

7)   IsNullOrEmpty() 方法,检查指定的字符串是否为 string.Empty null示例:

bool bool7 = string.IsNullOrEmpty("");      //true

bool bool8 = string.IsNullOrEmpty(null);    //true

bool bool9 = string.IsNullOrEmpty(" ");     //false

 

8)   IsNullOrEmpty() 方法,检查指定的字符串是否为 string.Emptynull 或仅由空白字符组成。示例:

bool bool10 = string.IsNullOrWhiteSpace("");    //true

bool bool11 = string.IsNullOrWhiteSpace(null);  //true

bool bool12 = string.IsNullOrWhiteSpace(" ");   //true

bool bool13 = string.IsNullOrWhiteSpace("1");   //false

 

9)   CompareOrdinal() 方法,通过计算每个字符串中相应 System.Char 对象的数值来比较两个指定的 System.String 对象。示例:

int int3_1 = string.CompareOrdinal("abc123", "abc123");     //0

int int3_2 = string.CompareOrdinal("abc123", "def123");     //-3

int int3_3 = string.CompareOrdinal("dec123", "abc123");     //3

 

4.   string 的常用实例方法

1)   CompareTo() 方法(+ 2 重载),比较两个字符串。示例:

int int4 = "acd".CompareTo("abc");  //1

int int5 = "123".CompareTo("135");  //-1

int int6 = "".CompareTo("");    //0

注:该方法与静态方法 CompareTo() 类似。

 

2)   Contains() 方法(+ 2 重载),查找此实例中是否包含指定的字符串。示例

bool bool14 = "abc123".Contains("c1");  //true

bool bool15 = "abc123".Contains("c2");  //false

 

3)   StartsWith() 方法(+ 2 重载),查找此实例开头是否为指定的字符串。示例:

bool bool16 = "abc123".StartsWith("ab");    //true

bool bool17 = "abc123".StartsWith("bc");    //false

bool bool18_1 = "abc".StartsWith("abc");    //true

 

4)   EndsWith() 方法(+ 2 重载),查找此实例末尾是否为指定的字符串。示例:

bool bool18 = "abc123".EndsWith("23");      //true

bool bool19 = "abc123".EndsWith("12");      //false

bool bool20_1 = "abc".EndsWith("abc");      //true

 

5)   Equals() 方法(+ 2 重载),比较此实例是否与指定的字符串的值相等。示例:

bool bool20 = "abc123".Equals("abc123");    //true

bool bool21 = "abc123".Equals(" abc123");   //false

bool bool21_1 = "a".Equals("A", StringComparison.CurrentCulture);           //false

bool bool21_2 = "a".Equals("A", StringComparison.CurrentCultureIgnoreCase); //true

注:该方法与静态方法 Equals() 类似。

 

6)   GetTypeCode() 方法,获取此实例对应的 System.TypeCode 枚举值。该方法实现于 System.IConvertible 接口,所有的基础数据类型都实现了该接口。示例:

TypeCode tc1 = "123".GetTypeCode(); //TypeCode.String

 

7)   IndexOf() 方法(+ 8 重载),获取指定字符或字符串在此实例中【第一次出现的索引,索引从零开始。示例:

int int7 = "abc123".IndexOf("b");   //1

 

8)   IndexOfAny() 方法(+ 2 重载),获取指定的字符数组的任意字符在此实例中【第一次出现的索引,索引从零开始。示例:

int int8 = "abc123".IndexOfAny(new char[] { '2', '3', '1' });    //3

注:可见,在查找前字符数组进行了升序排序,并没有按照索引顺序匹配。

 

9)   LastIndexOf() 方法(+ 8 重载),获取指定字符或字符串在此实例中【最后一次出现的索引,索引从零开始。示例:

int int9 = "abc123123".LastIndexOf("1");    //6

 

10)  LastIndexOfAny() 方法(+ 2 重载),获取指定的字符数组的任意字符在此实例中【最后一次出现的索引,索引从零开始。示例:

int int10 = "abc123123".LastIndexOfAny(new char[] { '2', '3', '1' });    //8

注:可见,在查找前字符数组进行了降序排序,并没有按照索引顺序匹配。

 

11)  Insert() 方法,返回在此实例的指定索引处插入字符串后的新字符串,索引从零开始。示例:

string str16 = "abc123".Insert(0, "lcl");   //lclabc123

 

12)  PadLeft() 方法(+ 1 重载),返回在此实例的【左侧】填充指定的字符来达到指定的长度。示例:

string str17 = "abc123".PadLeft(6, 'x');    //abc123

string str18 = "abc123".PadLeft(8, 'x');    //xxabc123

 

13)  PadRight() 方法(+ 1 重载),返回在此实例的【右侧】填充指定的字符来达到指定的长度。示例:

string str19 = "abc123".PadRight(6, 'x');   //abc123

string str20 = "abc123".PadRight(8, 'x');   //abc123xx

 

14)  Remove() 方法(+ 1 重载),返回在此实例中移除指定起始位置和数量后的字符串,索引从零开始。示例:

string str21 = "abc123".Remove(3, 1);   //abc23

 

15)  Replace() 方法(+ 1 重载),返回此实例在指定的旧值被新值替换后的字符串。示例:

string str22 = "abc123".Replace("abc", "def");   //def123

 

16)  Split() 方法(+ 5 重载),返回此实例在指定的字符数组分割后的字符串数组。示例:

char[] separator = { ' ', ',' };

StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries;

string[] strs1 = ",a b,c".Split(separator);             //["", "a", "b", "c"]

string[] strs2 = ",a b,c".Split(separator, options);    //["a", "b", "c"]

string[] strs3 = ",a b,c".Split(separator, 3);          //["", "a", "b,c"]

string[] strs4 = ",a b,c".Split(separator, 3, options); //["a", "b", "c"]

string[] strs5 = "abc".Split(separator, options);       //["abc"]

string[] strs6 = "".Split(separator, options);          //[]

 

17)  Substring() 方法(+ 1 重载),在此实例中检索指定起始位置至指定长度的子字符串,索引从零开始。示例:

string str23 = "abc123".Substring(1);       //bc123

string str24 = "abc123".Substring(1, 2);    //bc

string str24_1 = "abc123".Substring(0);     //abc123

string str24_2 = "abc123".Substring(6);     //""

string str24_3 = "abc123".Substring(7);     //System.ArgumentOutOfRangeExceptionstartIndex 不能大于字符串长度。

string str24_4 = "STAT items:1:number 2";

string str24_5 = str24_4.Substring(11, str24_4.LastIndexOf(':') - 11);  //1 str24_4.Substring(11("1"), 12 - 11);

 

18)  ToCharArray() 方法(+ 1 重载),将此实例复制到字符数组中,且可指定起始位置及长度,索引从零开始。示例:

char[] chars1 = "".ToCharArray();           //[]

char[] chars2 = "abc".ToCharArray();        //['a', 'b,', 'c']

char[] chars3 = "abc".ToCharArray(1, 1);    //['b']

 

19)  ToLower() 方法(+ 1 重载),返回此实例的【小写】形式的副本。示例:

string str25 = "ABc123".ToLower();          //abc123

 

20)  ToUpper() 方法(+ 1 重载),返回此实例的【大写】形式的副本。示例:

string str26 = "abC123".ToUpper();          //ABC123

 

21)  TrimStart() 方法(+ 1 重载),移除此实例中的【前导】空格 或 匹配指定字符数组的字符。示例:

string str27 = " okakabcok ".TrimStart();               //|okakabcok |

string str28 = " okakabcok ".TrimStart('k', ' ', 'o');  //|akabcok |

 

22)  TrimEnd() 方法(+ 1 重载),移除此实例中的【尾部】空格 或 匹配指定字符数组的字符。示例:

string str29 = " okabcakok ".TrimEnd();                 //| okabcakok|

string str30 = " okabcakok ".TrimEnd('k', ' ', 'o');    //| okabca|

 

23)  Trim() 方法(+ 1 重载),移除此实例中的【首尾】空格 或 匹配指定字符数组的字符。示例:

string str31 = " okabcakok ".Trim();                    //|okabcakok|

string str32 = " okabcakok ".Trim('k', ' ', 'o');       //|abca|

 

5.   string 的常用扩展方法

Ø  string 的扩展主要是借助了 IEnumerable<char> 接口的扩展,使用这些扩展方法之前,首先需要引入 System.Linq 命名空间。

1)   获取第一个字符

char char1 = "abc123".FirstOrDefault();     //a

 

2)   获取指定索引处的字符,索引从零开始

char char2 = "abc123".ElementAt(1);         //b

 

3)   反转字符串

string str36 = new string("abc123".Reverse().ToArray());    //321cba

 

4)   字符串排序

string str37 = new string("132cab".OrderBy(o => o).ToArray());              //123abc

string str38 = new string("132cab".OrderByDescending(o => o).ToArray());    //cba321

 

5)   去除字符串中的重复字符

string str39 = new string("abc123abc123".Distinct().ToArray()); //abc123

 

Ø  总之,IEnumerable<char> 接口的扩展方法,字符串对象都可以运用之,因为 string 就是一个 char 类型的集合,这里就不一一列举了。

 

6.   string 的使用技巧

1)   连接字符串

string str50 = null;

string str51 = str50 + "abc";                   //abc

string str52 = string.Format("{0}abc", str50);  //abc

 

2)   生成字符串

string str56 = string.Join(",", Enumerable.Range(1, 5));    //1,2,3,4,5

string str57 = string.Empty.PadLeft(5, 'a');                //aaaaa

 

3)   获取字符串宽度

string str61 = "获取字符串宽度";

using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))

{

    int fontSize = 9;

    SizeF sizeF = graphics.MeasureString(str61, new Font("宋体", fontSize));

    float width = sizeF.Width;  //90.49804

}

说明:这里需要使用 System.Drawing.Graphics 类,需要另外引用 System.Drawing.dll 程序集。

注:WinForm 中还可以使用 Control 类,获取 Graphics 的实例,例如:

Graphics graphics = (new System.Windows.Forms.Control()).CreateGraphics();

 

4)   字符串与字节数组互转

//字符串 转为 字节数组

byte[] bytes1 = Encoding.Default.GetBytes("");     //[165, 193]

byte[] bytes2 = Encoding.Default.GetBytes("");     //[165, 235]

byte[] bytes3 = Encoding.Default.GetBytes("");     //[206, 210]

byte[] bytes4 = Encoding.Default.GetBytes("a");     //[97]

byte[] bytes5 = Encoding.Default.GetBytes("A");     //[65]

byte[] bytes6 = Encoding.Default.GetBytes("1");     //[49]

byte[] bytes7 = Encoding.Default.GetBytes("#");     //[35]

byte[] bytes8 = Encoding.Default.GetBytes("");      //[]

byte[] bytes9 = Encoding.Default.GetBytes(" ");     //[32]

byte[] bytes10 = Encoding.Default.GetBytes(".");    //[46]

byte[] bytes11 = Encoding.Default.GetBytes("");   //[161, 163]

byte[] bytes12 = Encoding.Default.GetBytes(",");    //[44]

byte[] bytes13 = Encoding.Default.GetBytes("");   //[163, 172]

//字节数组 转为 字符串

string str66 = Encoding.Default.GetString(bytes3);  //

string str67 = Encoding.Default.GetString(bytes4);  //a

 

5)   字符串与 Base64编码 互转

string str71 = "字符串与 Base64编码 互转";

//字符串 转为 Base64编码

byte[] byte21 = Encoding.Default.GetBytes(str71);

string str72 = Convert.ToBase64String(byte21);     //19a3+7Su0+sgQmFzZTY0seDC6yC7pdeq

//Base64编码 转为 字符串

byte[] byte22 = Convert.FromBase64String(str72);

string str73 = Encoding.Default.GetString(byte22);  //字符串与 Base64编码 互转

 

7.   char 的常用静态方法

1)   IsWhiteSpace() 方法(+ 2 重载),查找指定位置的字符是否为空白字符。例:

bool bool1_1 = char.IsWhiteSpace(' ');        //true

bool bool1_2 = char.IsWhiteSpace('a');        //false

bool bool1_3 = char.IsWhiteSpace("a bc", 1);  //true

bool bool1_4 = char.IsWhiteSpace("a bc", 2);  //false

 

2)   IsPunctuation() 方法(+ 2 重载),查找指定位置的字符是否为标点符号。例:

bool bool2_1 = char.IsPunctuation('a');         //false

bool bool2_2 = char.IsPunctuation(',');         //true

bool bool2_3 = char.IsPunctuation("a,bc", 1);   //true

bool bool2_4 = char.IsPunctuation("abc", 1);  //true

posted @ 2017-09-14 19:57  Abeam  阅读(5433)  评论(2编辑  收藏  举报