[C#]系列文章——关于C#,你应该知道的2000件事情(001)

2023-05-14,

 系列文章从关于C#,你应该知道的2000件事情翻译

1. 使用foreach语句遍历字符串

可以使用foreach语句遍历字符串中的每个字符,迭代变量是char类型。

string secret = "Kint is Keyser Soze";
StringBuilder sbObfuscate = new StringBuilder();
foreach (char c in secret)
    sbObfuscate.Append((char)(c + 3));
Console.WriteLine(sbObfuscate);

2. TryParse方法指示类型转换操作是否成功

可以使用Parse方法将代表数字的字符串转化为和它等效的数值类型。

string numberString = "108";
int number = int.Parse(numberString);

以上操作会实现转换:"108" à 108。但是上述操作存在一个问题:如果字符串代表的不是相关的数值类型,或是代表的数字超过了要转换类型的范围,会产生FormatException或 OverflowException异常。

int n1 = int.Parse("3.4");//FormatException

可以通过使用TryParse的方法避免异常。如果转换操作成功,则转换值存储在输出参数中,TryParse返回true。如果转换操作不成功,输出参数不会写入,TryParse的返回false,不会抛出异常。

int n1;
if (int.TryParse("3.4", out n1))
    Console.WriteLine("Parse worked--n1 contains number");
else
    Console.WriteLine("Can't parse");

3.字符串是不可变的

C#中,字符串(System.String Type)是不可变的,操作字符串的函数(方法)不会改变字符串的实例,实际上返回字符串的一个新的实例。例如,可以使用Replace方法替换字符串的一部分,可以将结果赋值给原始的那个字符串或是一个新的字符串。

  如果忘记了字符串是不可变的,可能会将Replace方法执行的结果赋值给其他的变量。而编译器对此不会提醒或是警告。

string quote = "Go to Heaven for the climate, Hell for the company.";
Console.WriteLine(quote);
// Does NOT change quote.  Rather, it creates 
//a new string, which we don't store anywhere
quote.Replace("Hell", "Minnesota");
Console.WriteLine(quote);

在C#中,字符串创建以后就是不可变的,但是可以通过把对字符串的操作结果赋值给新的字符串变量来改变旧字符串的值。

string s1 = "AGORA";
s1 = s1.Replace('A', 'Z');   // Replace A's with Z's

在这种情况下,原来的字符串s1被销毁,包含操作结果的字符串赋值给s1。在大部分的场合,字符串是不可变的并不影响什么,因为仍然可以通过将操作结果赋值给原来的字符串变量来改变字符串的值。

但是,在考虑对同一字符串重复相同的字符串的操作时的效率时,字符串是不可变的是非常关键的。使用字符串连接操作符(+)是非常方便的,但是效率不高,因为每次连接操作都会创建一个新的字符串对象。

string s1 = "";
for (int i = 0; i < 50000; i++)
    s1 = s1 + i.ToString();//+对象操作每次都会创建一个新的string
可以通过StringBuilder类的Append方法提高以上代码的效率,Append方法避免在每次迭代中创建新的string对象。
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < 50000; i++)
    sb.Append(i.ToString());
后者的效率至少是前者的30倍。

4.获取包含代理编码对(Surrogate Pairs)的字符串的长度

可以使用string.Length属性来获取字符串的长度(字符的个数),但是,注意,这只有在字符串的Unicode代码点不大于U+FFFF时可以正常获取,Unicode代码点集合也称为BMP(BasicMultilingual Plane)—基本多语言平面.

  而BMP之外的Unicode代码点的代表是使用4字节代理编码对的 UTF-16 ,而BMP的Unicode代码点使用的是2字节.

  为了正确统计代码点可能包含高于U+FFFF字符串的字符个数,可以使用StringInfo类(System.Globalization)

string simple = "abc";// 3 Latin (ASCII) characters
// 3 character string where one character is a surrogate pair
string containsSurrogatePair = "AC";
// Length=3 (correct)
Console.WriteLine(string.Format("Length 1 = {0}", simple.Length)); 
// Length=4 (not quite correct)
Console.WriteLine(string.Format("Length 2 = {0}", containsSurrogatePair.Length));
 
// Better, reports Length=3
StringInfo si = new StringInfo(containsSurrogatePair);
Console.WriteLine(string.Format("Length 3 = {0}", si.LengthInTextElements));

尽管如此,在大部分的时候,仍然可以使用string.Length获取字符串的长度(字符个数),但是应该注意Length属性返回组成字符串的char对象的个数,而这和实际上的Unicode字符个数不一样的.

string simple = "abc";// 3 Latin (ASCII) characters
string other = "ā丁";// 2 other characters: U+0100, E+4E01
 
Console.WriteLine(string.Format("Length 1 = {0}", simple.Length));//3
Console.WriteLine(string.Format("Length 2 = {0}", other.Length));//2

5. 通过正则表达式在字符串中检查有效字符

using System.Text.RegularExpressions;
public bool IsAlphabetic(string s)
{
    Regex r = new Regex(@"^[a-zA-Z]+$");//判断字符串是否由字母组成
    //Regex r = new Regex(@"^[0-9]+$"");//判断字符串是否由数组组成
    return r.IsMatch(s);
}

以上方法判断字符串 s 是否由字母组成,注意一下几点:

^  代表字符串的开始

[a..zA..Z] 小写或大写字母

+ 字符串的字符可以重复

$ 字符串的结束

《[C#]系列文章——关于C#,你应该知道的2000件事情(001).doc》

下载本文的Word格式文档,以方便收藏与打印。