赞
踩
在C#语言中,字符串是System.String类的一个引用类型,但与其他引用类型不同的是,C#将字符串视为一个基本类型,它可以申请为一个常量,也可以直接给它赋值。由于C#中的字符串是由System.String类派生而来的引用对象,因此可以使用String类的方法来对字符串进行各种操作。下面通过几个例子来讲述String类的几个重要方法以及字符串拘留池机构。
1、字符串的复制:
(1)、String.Copy(str):参数str为要复制的字符串,它回返回一个与该字符串相等的字符串
(2)、SreStr.CopyTo(StartOfSreStr, DestStr, StartOfDestStr, CopyLen):它必须被要复制的字符串实例调用,它可以实现复制其中某一部分到目标字符串的指定位置
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string SourceStr = "hello everyOne!!";
string CopyStr = String.Copy(SourceStr);
char[] CopyToStr = new char[20];
SourceStr.CopyTo(6, CopyToStr, 0, 10); //该函数必须有一个实例调用,并且第二个参数为字符串数组
Console.WriteLine("CopyStr = " + CopyStr);
Console.Write("CopyToStr = ");
Console.WriteLine(CopyToStr);
}
}
}
结果:CopyStr = hello everyOne!!
CopyToStr = everyOne!!

Copy()方法只适用于需要吧某个字符串完整复制到另一个字符串中的情况,相比之下CopyTo()则比较灵活。
2、字符串的比较:
String类字符串比较大概有4种方法:Compare(),CompareTo(), CompareOrdinal()和Equals(). Compare()方法是CompareTo()的静态版本.而Equals()与”==”是等价的,只要使用”==”运算符,就会调用Equals()方法。CompareOrdinal()对两个字符串进行比较,不考虑本地化语言和文化。
(1)、String.Compara(str1, str2):
(2)、String.CompareTo(string value):该实例与value的值进行比较。返回:如果string大于value则返回1,如果string小于value则返回-1,如果两个相等则返回0。
(3)、String.CompareOrdinal(str1, str2):是将整个字符串每5个字符(10个字节)分成一组,然后逐个比较,找到第一个不相同的ASCII码后退出循环。并且求出两者的ASCII码的差。【我不明白为什么要实现的如此麻烦。但是在CLR via C#上有这样的话:这个方法比其他方法都要快。应该是有一定道理的吧。所以当我们比较大小的时候,尽量使用CompareOrdinal方法。】
(4)、String.Equals(string value):用于比较两个字符串是否相等。返回:如果和String相等则为true;否则为false。【由于是非安全代码的比较,所以效率要比我们用安全代码高得多】
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
int nResult = 0;
bool bResult = false;
string str1 = "you are very happy!!";
string str2 = "I am very happy!!";
string str3 = "I am very happy!!";
nResult = string.Compare(str1, str2);
Console.WriteLine("Compare(str1, str2) = " + nResult);
nResult = str1.CompareTo(str2);
Console.WriteLine("str1.CompareTo(str2) = " + nResult);
nResult = string.CompareOrdinal(str1, str2);
Console.WriteLine("CompareOrdinal(str1, str2) = " + nResult);
bResult = str2.Equals(str3);
Console.WriteLine("str2.Equals(str3) = " + bResult);
Console.WriteLine("str2 == str3 " + (str2 == str3 ? true : false));
}
}
}
结果:Compare(str1, str2) = 1
str1.CompareTo(str2) = 1
CompareOrdinal(str1, str2) = 48
str1.Equals(str2) = True
str2 == str3 True

其实字符串的比较还有一个方法Object.ReferenceEquals(str1, str4),不过它是比较两个字符串的对象引用是否相同,例子与使用请查看第11条:字符串拘留池机构。
3、字符串的查找:
(1)、String.Contains(Findstr):参数:Findstr为要查找的字符或字符串;功能:找指定字符串是否包含一个字串,返回值的boolean类型,即只有true和false。
(2)、String.IndexOf(Findstr):参数:Findstr为要查找的字符或字符串;功能:查找FindStr在字符串中第一次出现的位置,返回值为第一次出现的下标,没有找到则返回-1.
(3)、String.LastIndexOf(FindStr):参数:Findstr为要查找的字符或字符串;功能:查找FindStr在字符串中最后一次出现的位置,返回值为最后一次出现的下标,没有找到则返回-1。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
int nResult = 0;
bool bResult = false;
string str = "hello everyOne!!";
bResult = str.Contains("e");
Console.WriteLine("Contains(\"e\") = " + bResult);
nResult = str.IndexOf("e");
Console.WriteLine("IndexOf(\"e\") = " + nResult);
nResult = str.LastIndexOf("e");
Console.WriteLine("LastIndexOf(\"e\") = " + nResult);
}
}
}
结果:Contains("e") = True
IndexOf("e") = 1
LastIndexOf("e") = 13

(4)、String.IndexOf(Findstr)还有一个重载函数String.indexof(),它的用法如下:
(5)、String.indexof():在字符串中从前向后定位字符和字符串;所有的返回值都是指在字符串的绝对位置,如为空则为-1 。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
int nResult = 0;
string str = "hello everyOne!!";
nResult = str.IndexOf('e'); //查找该字符串中的第一次'e'出现位置
Console.WriteLine("IndexOf('e') = " + nResult);
nResult = str.IndexOf('e', 1); //查找该字符串中的第一次'e'出现位置
Console.WriteLine("IndexOf('e', 1) = " + nResult);
nResult = str.IndexOf('e', 5, 4); //从前向后定位从第5位到第9位中'e'出现的位置;
Console.WriteLine("IndexOf('e', 5, 4) = " + nResult);
}
}
}
结果:IndexOf('e') = 1
IndexOf('e', 1) = 1
IndexOf('e', 5, 4) = 6

4、字符串的截取:
(1)、String.SubString(StartIndex):参数:StartIndex为要进行截取的开始下标;功能:保留字符串中下标从StartIndex开始后面的全部字符串。
(2)、String.SubString(StartIndex, Len):参数:StartIndex为要开始截取的下标,Len为要截取的长度;功能:保留字符串中下标从StartIndex开始后面的Len个长度的字符串。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
int nResult = 0;
string str = "hello everyOne!!";
string OnePareStr = str.Substring(5);
string TwoPareStr = str.Substring(5, 6);
Console.WriteLine("str.Substring(5) = " + OnePareStr);
Console.WriteLine("str.Substring(5, 6) = " + TwoPareStr);
}
}
}
结果:strstr.Substring(5) = everyOne!!
str.Substring(5, 6) = every

5、字符串的分割:
String.Split(SplitCh):参数:SplitCh为分割的字符;功能:将字符串一SplitCh进行分割,它的返回值是一个字符串数组。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = "hello everyOne!!";
string[] destStr = str.Split('e');
Console.Write("str.Split('e') = ");
foreach (string outstr in destStr)
{
Console.Write(outstr);
Console.Write(" ");
}
}
}
}
结果:str.Split('e') = h llo v ryOn !!

6、字符串的合并:
(1)、String.Concat(str1, str2, …., strn):将n个字符串连接,中间没有连接符
(2)、String.Join(SplitCh, array):参数:SplitCh为合并后的分隔符,array为要合并的字符串数组;功能:将字符串书组合并成一个字符串,每个元素之间用SplitCh隔开
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str1 = "hello, ";
string str2 = "I am very happy!!";
string[] array= {"hello", "I am", "very happy!!"};
string ConcatStr = string.Concat(str1, str2);
String JoinStr = string.Join("|", array);
Console.WriteLine("string.Concat(str1, str2) = " + ConcatStr);
Console.WriteLine("string.Join('-', array) = " + JoinStr);
}
}
}
结果:string.Concat(str1, str2) = hello, I am very happy!!
string.Join('-', array) = hello|I am|very happy!!

其实字符串连接也可以用 ‘+’ 来实现。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str1 = "hello, ";
string str2 = "I am very happy!!";
string DestStr = str1 + str2;
Console.WriteLine("str1 + str2 = " + DestStr);
}
}
}
结果:str1 + str2 = hello, I am very happy!!
7、字符串的替换:
String.Replace(SreStr, ChangeStr):参数:SreStr为要替换的原字符串,ChangeStr为用来替换的字符串。作用:用ChangeStr来替换字符串中的SreStr.
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = "I am very happy!!";
string DestStr = str.Replace("very", "not");
Console.WriteLine("str.Replace(\"very\", \"not\") = " + DestStr);
}
}
}
结果:str.Replace("very", "not") = I am not happy!!
8、字符串的插入与填充:
(1)、String.Insert(index, str):index是需要插入的位置,str是要插入的字符;
(2)、String.PadRight(Len, ch):参数:Len为字符串的总长度,ch为用来填充的字符。作用:如果字符串上都不够Len,则在结尾用ch来填充
(3)、String.PadLeft(Len, ch):参数:Len为字符串的总长度,ch为用来填充的字符。作用:如果字符串上都不够Len,则在开始处用ch来填充
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = "I am happy!!";
string str1 = str.Insert(5, "very ");
string str2 = str1.PadLeft(30, ' ');
string str3 = str1.PadRight(30, ' ');
Console.WriteLine("str.Insert(6, \"very \") = " + str1);
Console.WriteLine("str1.PadLeft(30, ' ') = " + str2);
Console.WriteLine("str1.PadRight(30, ' ') = " + str3);
}
}
}
结果:str.Insert(6, "very ") = I am very happy!!
str1.PadLeft(30, ' ') = I am very happy!!
str1.PadRight(30, ' ') = I am very happy!!

9、字符串的删除:
(1)、String.Trim():删除字符串中开始和结尾处的空格。
(2)、string.Trim(Param char[]):参数:char[]为想要去掉的字符数组。功能:去掉字符串开始处和结尾处char[]中的所有字符。
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = " #$$I am very happy!! ##$$ ";
Console.WriteLine("str.Trim() = " + str.Trim());
Console.WriteLine("str.Trim(' ', '#', '$') = " + str.Trim(' ', '#', '$'));
}
}
}
结果:str.Trim() = #$$I am very happy!! ##$$
str.Trim(' ', '#', '$') = I am very happy!!
String.Trim()只能删除字符串开始与结尾的指定字符,而Remove()则可以删除任意位置的字符(当然,数组越界则不行呦)。
(4)、String.Remove(Start):Start为需要删除的起始位置,该方法是将位置后的所有字符全部删除
(5)、String.Remove(Start, Len):Len是指需要删除的长度,与上面格式不同的是它是从起始位置开始删除Len个字符
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = " #I am very happy!! ## ";
Console.WriteLine("str.Remove(22) = " + str.Remove(22));
Console.WriteLine("str.Remove(22, 2) = " + str.Remove(22, 2));
}
}
}
结果:str.Remove(22) = #I am very happy!!
str.Remove(22, 2) = #I am very happy!!##
10、字符串的大小写转换:
(1)、String.ToLower():将字符串转化为小写形式
(2)、String.ToUpper():将字符串转换威大写形式
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str = "Hello, I am very happy!!";
Console.WriteLine("str.ToLower() = " + str.ToLower());
Console.WriteLine("str.ToUpper() = " + str.ToUpper());
}
}
}
结果:str.ToLower() = hello, i am very happy!!
str.ToUpper() = HELLO, I AM VERY HAPPY!!
ToLower()和ToUpper()两种方法都必须用一个string实例来调用,并且都会返回一个转换完成的新字符串。
11、字符串拘留池机构
同一个程序中,即使将同一个字符串复值给多个字符串,系统就会多次分配内存空间,这样不仅浪费内存,也会影响系统性能,为此,.Net提出了字符串拘留池机制。
拘留池机制原理:
使用拘留池后,当CLR启动后,会在内部创建一个容器,该容器的键为字符串的内容,值则时字符串在托管堆上的引用。这样的话,每次需要分配一个新字符串对象时,在分配内存之前先会检测容器中是否包含了该字符串对象,存在则返回已经存在的字符串对象的引用,不存在的话才会新分配对象,把它添加到内部容器中,然后再返回该对象的引用。【如果用new分配一个字符串对象,字符串拘留池机制不会起作用】,原理如下图:
定义一个字符串s1 = “123”:
如果此时在给s2也赋值123时,则s2字符串变量s2也指向字符串对象“123”:
那么CLR保存的字符串拘留池的容器可以访问吗?结果是肯定哒,System.String类中提供了两个静态方法可以进行访问:
(1)、public static String Intern (String s):返回字符串s在字符串拘留池中对应的引用,如果该字符串不在字符串拘留池中,那么会新分配一个字符串对象并添加到字符串拘留池中同时返回该字符串的引用。
(2)、public static String IsInterned (String s): 功能与上个方法相似。只是当字符串s不在字符串拘留池中时,不会分配新的对象,并返回null。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringTest
{
class Program
{
static void Main(string[] args)
{
string str1 = "I am very happy!!";
string str2 = "I am very happy!!";
Console.WriteLine(object.ReferenceEquals(str1, str2)); //str1与str2的引用相同
char[] array1 = { 'I', ' ', 'a', 'm', ' ', 'v', 'e', 'r', 'y', ' ', 'h', 'a', 'p', 'p', 'y', '!', '!'};
string str4 = new string(array1);
//str1与str4引用不同的话,就说明使用new时拘留池机制没有发挥作用
Console.WriteLine(Object.ReferenceEquals(str1, str4));
//str2存在容器中,所以返回的是一个对象的引用
Console.WriteLine("IsInterned(str2) = " + string.IsInterned(str2));
char[] array2 = { 't', 'e', 's', 't'};
string str5 = new string(array2);
//因为str5使用new分配的,所以str5不存在与内部容器中,所以如果IsInterned(str5)返回null,
//则说明该方法不会将其添加到拘留池中
string str6 = string.IsInterned(str5);
Console.Write("IsInterned(str5) = ");
Console.WriteLine(str6 == null ? "null" : "not null");
//同理如果IsInterned(str5)返回null,则说明Intern()方法会先将其添加到拘留池中,然后再返回一个对象引用
Console.WriteLine("Intern(str6) = " + string.Intern(str5));
//再用IsInterned()验证下intern()方法是否将其添加进了容器
string str7 = string.IsInterned(str5);
Console.Write("IsInterned(str5) = ");
Console.WriteLine(str7 == null ? "null" : "not null");
}
}
}
结果:True
False
IsInterned(str2) = I am very happy!!
IsInterned(str5) = null
Intern(str6) = test
IsInterned(str5) = not null

拘留池机制缺点:
拘留池机制每次在分配内存之前,先回在容器内部查找该字符串是否存在,这样就导致,如果一个程序中字符串赋值或者重复读很低甚至没有重复时,字符串拘留池机制不仅不会洁身内存,相反会因为CLR额外的保留了一个存储字符串池的容器,并且在每次进行字符串赋值时都要额外的检查这个容器而带来负面影响。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。