* 说明:第2部分:第14章:字符、字符串和文本处理(P280) * 14.1 本章内容: · 字符 · System.String类型 · 高效率构造字符串 · 获取对象的字符串表示:ToString · 解析字符串来获取对象:Parse · 编码:字符和字节的相互转换 · 安全字符串
using System; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading; using System.Windows.Forms; public static class Program { public static void Main(String[] args) { GetNumericValue.Go(); CharConvert.Go(); ComparingStringForEquality.Go(); ComparingStringsForSorting.Go(); Interning.Go(); UsingStringInfo.Go(); UsingStringBuilder.Go(); Formatting.Go(); CustomFormatter.Go(); Encodings.Go(); EncodingProperties.Go(); CodePageConverter.Go(args); Base64Encoding.Go(); UsingSecureString.Go(); } } /// <summary> /// /// </summary> internal static class GetNumericValue //P280 { public static void Go() { Double d; // ‘\u0033’ 是“数字 3” d = Char.GetNumericValue('\u0033'); // 也可以直接使用‘3’ Console.WriteLine(d.ToString()); // 显示 "3" // ‘\u00bc’ 是普通分数四分值一“('¼')” d = Char.GetNumericValue('\u00bc'); Console.WriteLine(d.ToString()); // Displays "0.25" // ‘A’是 “大写拉丁字母 A” d = Char.GetNumericValue('A'); Console.WriteLine(d.ToString()); // Displays "-1" } } /// <summary> /// 字符转换 P281 /// </summary> internal static class CharConvert { public static void Go() { Char c; Int32 n; // 通过 c = (Char)65; Console.WriteLine(c); // 显示 "A" n = (Int32)c; Console.WriteLine(n); // 显示 "65" c = unchecked((Char)(65536 + 65)); //unchecked 允许发生溢出 Console.WriteLine(c); // 显示 "A" // Convert 数字 <-> 字符的相互转换 c = Convert.ToChar(65); Console.WriteLine(c); // Displays "A" n = Convert.ToInt32(c); Console.WriteLine(n); // Displays "65" // 演示Convert的范围检查 try { c = Convert.ToChar(70000); // 对16位来说过大 Console.WriteLine(c); // 不执行 } catch (OverflowException) { Console.WriteLine("Can't convert 70000 to a Char."); } // IConvertible 数字 <-> 字符的转化 c = ((IConvertible)65).ToChar(null); Console.WriteLine(c); // Displays "A" n = ((IConvertible)c).ToInt32(null); Console.WriteLine(n); // Displays "65" } } /// <summary> /// 演示了了序号比较和对语言文化敏感的比较的区别 P288 /// </summary> internal static class ComparingStringForEquality { public static void Go() { String s1 = "Strasse"; String s2 = "Straße"; Boolean eq; // 比较返回非零值 eq = String.Compare(s1, s2, StringComparison.Ordinal) == 0; Console.WriteLine("Ordinal comparison: '{0}' {2} '{1}'", s1, s2, eq ? "==" : "!="); // 面向在德国(de)说德语(de)的人群 //正确的比较字符串 CultureInfo ci = new CultureInfo("de-DE"); // Compare 返回零值,表示相等 eq = String.Compare(s1, s2, true, ci) == 0; Console.WriteLine("Cultural comparison: '{0}' {2} '{1}'", s1, s2, eq ? "==" : "!="); } } /// <summary> /// 演示语言文化对字符串排序的重要性,并展示了执行字符串比较的各种方式 /// </summary> internal static class ComparingStringsForSorting { public static void Go() { String output = String.Empty; String[] symbol = new String[] { "<", "=", ">" }; Int32 x; CultureInfo ci; // 以下代码演示了在不同语言文化中 // 字符串的比较方式也有所不同 String s1 = "coté"; String s2 = "côte"; // 为法国法语排序字符串 ci = new CultureInfo("fr-FR"); x = Math.Sign(ci.CompareInfo.Compare(s1, s2)); output += String.Format("{0} Compare: {1} {3} {2}", ci.Name, s1, s2, symbol[x + 1]); output += Environment.NewLine; // 为日本日语排序字符串 ci = new CultureInfo("ja-JP"); x = Math.Sign(ci.CompareInfo.Compare(s1, s2)); output += String.Format("{0} Compare: {1} {3} {2}", ci.Name, s1, s2, symbol[x + 1]); output += Environment.NewLine; // 为当前线程的当前语言文化排序字符串 ci = Thread.CurrentThread.CurrentCulture; x = Math.Sign(ci.CompareInfo.Compare(s1, s2)); output += String.Format("{0} Compare: {1} {3} {2}", ci.Name, s1, s2, symbol[x + 1]); output += Environment.NewLine + Environment.NewLine; // 以下代码演示了如果将CompareInfo.Compare的 // 高级选项应用于两个日语字符串 // 一个字符串代表用平假名写成的同一个单词“shikansen”(新干线) // 另一个字符串代表用片假名写成的同一个单词 s1 = "しんかんせん"; // ("\u3057\u3093\u304B\u3093\u305b\u3093") s2 = "シンカンセン"; // ("\u30b7\u30f3\u30ab\u30f3\u30bb\u30f3") // H以下是默认比较结果 ci = new CultureInfo("ja-JP"); x = Math.Sign(String.Compare(s1, s2, true, ci)); output += String.Format("Simple {0} Compare: {1} {3} {2}", ci.Name, s1, s2, symbol[x + 1]); output += Environment.NewLine; // 以下是忽略日语假名的比较结果 CompareInfo compareInfo = CompareInfo.GetCompareInfo("ja-JP"); x = Math.Sign(compareInfo.Compare(s1, s2, CompareOptions.IgnoreKanaType)); output += String.Format("Advanced {0} Compare: {1} {3} {2}", ci.Name, s1, s2, symbol[x + 1]); MessageBox.Show(output, "Comparing Strings For Sorting"); } } /// <summary> /// 字符串留用, /// </summary> internal static class Interning//P292 { public static void Go() { String s1 = "Hello"; String s2 = "Hello"; Console.WriteLine(Object.ReferenceEquals(s1, s2)); // 显示 be 'False' //显示调用Intern, s1 = String.Intern(s1); s2 = String.Intern(s2); Console.WriteLine(Object.ReferenceEquals(s1, s2)); // 'True' } private static Int32 NumTimesWordAppearsIntern(String word, String[] wordlist) { // 这个方法假定wordlist中的所有数组元素都引用已留用的字符串 //但是要谨慎使用。虽然能局部的提升性能,但有可能会带来整体性能降低。 word = String.Intern(word); Int32 count = 0; for (Int32 wordnum = 0; wordnum < wordlist.Length; wordnum++) { if (Object.ReferenceEquals(word, wordlist[wordnum])) count++; } return count; } private static Int32 NumTimesWordAppearsEquals(String word, String[] wordlist) { Int32 count = 0; for (Int32 wordnum = 0; wordnum < wordlist.Length; wordnum++) { if (word.Equals(wordlist[wordnum], StringComparison.Ordinal)) count++; } return count; } } /// <summary> /// StringInfo类来处理字符串的文本元素的各种方式 /// </summary> internal static class UsingStringInfo { public static void Go() { // 以下字符串包含组合字符 String s = "a\u0304\u0308bc\u0327"; SubstringByTextElements(s); EnumTextElements(s); EnumTextElementIndexes(s); } private static void SubstringByTextElements(String s) { String output = String.Empty; StringInfo si = new StringInfo(s); for (Int32 element = 0; element < si.LengthInTextElements; element++) { output += String.Format( "Text element {0} is '{1}'{2}", element, si.SubstringByTextElements(element, 1), Environment.NewLine); } MessageBox.Show(output, "Result of SubstringByTextElements"); } private static void EnumTextElements(String s) { String output = String.Empty; TextElementEnumerator charEnum = StringInfo.GetTextElementEnumerator(s); while (charEnum.MoveNext()) { output += String.Format( "Text element at index {0} is '{1}'{2}", charEnum.ElementIndex, charEnum.GetTextElement(), Environment.NewLine); } MessageBox.Show(output, "Result of GetTextElementEnumerator"); } private static void EnumTextElementIndexes(String s) { String output = String.Empty; Int32[] textElemIndex = StringInfo.ParseCombiningCharacters(s); for (Int32 i = 0; i < textElemIndex.Length; i++) { output += String.Format( "Text element {0} starts at index {1}{2}", i, textElemIndex[i], Environment.NewLine); } MessageBox.Show(output, "Result of ParseCombiningCharacters"); } } /// <summary> /// 高效率的构造字符串 /// </summary> internal static class UsingStringBuilder { public static void Go() { // 构造一个StringBuilder来执行字符串操作 StringBuilder sb = new StringBuilder(); // 使用StringBuiler来执行一些字符串的操作 sb.AppendFormat("{0} {1}", "Jeffrey", "Richter").Replace(" ", "-"); //将 StringBuilder转化为 String 以便将所以字符串转化为大写 String s = sb.ToString().ToUpper(); //清除StringBuilder(分配新的char数组) sb.Length = 0; // 将全部字符大写的String加载到StringBuilder中,执行其他操作 sb.Append(s).Insert(8, "Marc-"); // 将StringBuilder 转化回 String. s = sb.ToString(); //向用户显示String Console.WriteLine(s); // "JEFFREY-Marc-RICHTER" } } /// <summary> /// 格式化字符串 /// </summary> internal static class Formatting { public static void Go() { Decimal price = 123.54M; String s = price.ToString("C", new CultureInfo("vi-VN")); MessageBox.Show(s); s = price.ToString("C", CultureInfo.InvariantCulture); MessageBox.Show(s); } } /// <summary> /// 提供定制格式化器 P304 /// </summary> internal static class CustomFormatter { public static void Go() { StringBuilder sb = new StringBuilder(); sb.AppendFormat(new BoldInt32s(), "{0} {1} {2:M}", "Jeff", 123, DateTime.Now); Console.WriteLine(sb); } private sealed class BoldInt32s : IFormatProvider, ICustomFormatter { public Object GetFormat(Type formatType) { if (formatType == typeof(ICustomFormatter)) return this; return Thread.CurrentThread.CurrentCulture.GetFormat(formatType); } public String Format(String format, Object arg, IFormatProvider formatProvider) { String s; IFormattable formattable = arg as IFormattable; if (formattable == null) s = arg.ToString(); else s = formattable.ToString(format, formatProvider); if (arg.GetType() == typeof(Int32)) return "<B>" + s + "</B>"; return s; } } } /// <summary> /// 编码:字符和字节的相互转化P310 /// </summary> internal static class Encodings { public static void Go() { // 准备编码的字符串 String s = "Hi there."; // 获取从Endoing派生的一个对象 // to encode/decode using UTF8 Encoding encodingUTF8 = Encoding.UTF8; //将字符串编码成字节数组 Byte[] encodedBytes = encodingUTF8.GetBytes(s); // 显示编好码的字节值 Console.WriteLine("Encoded bytes: " + BitConverter.ToString(encodedBytes)); // 将字节数组解码回字符串 String decodedString = encodingUTF8.GetString(encodedBytes); // 显示解码的字符串. Console.WriteLine("Decoded string: " + decodedString); } } /// <summary> /// 演示大多数属性及其含义P311 /// </summary> internal static class EncodingProperties { public static void Go() { foreach (EncodingInfo ei in Encoding.GetEncodings()) { Encoding e = ei.GetEncoding(); Console.WriteLine("{1}{0}" + "\tCodePage={2}, WindowsCodePage={3}{0}" + "\tWebName={4}, HeaderName={5}, BodyName={6}{0}" + "\tIsBrowserDisplay={7}, IsBrowserSave={8}{0}" + "\tIsMailNewsDisplay={9}, IsMailNewsSave={10}{0}", Environment.NewLine, e.EncodingName, e.CodePage, e.WindowsCodePage, e.WebName, e.HeaderName, e.BodyName, e.IsBrowserDisplay, e.IsBrowserSave, e.IsMailNewsDisplay, e.IsMailNewsSave); } } } internal static class CodePageConverter { public static void Go(String[] args) { if (args.Length != 4) { Console.WriteLine( "CodePageConverter <SrcFile> <SrcCodePage> <DstFile> <DstCodePage>{0}{0}" + "Examples:{0}" + " CodePageConverter InFile.txt 65001 OutFile.txt 1200{0}" + " => Converts from UTF-8 (codepage 65001) to UTF-16 (Little Endian){0}{0}" + " CodePageConverter InFile.txt 932 OutFile.txt UTF-8{0}" + " => Converts from shift-jis (codepage 932) to UTF-8", Environment.NewLine); return; } // Open the source stream using the specified encoding // Create the destination stream using the specified encoding using (StreamReader srcText = new StreamReader(args[0], GetEncoding(args[1]))) using (StreamWriter dstText = new StreamWriter(args[2], false, GetEncoding(args[3]))) { // Read from the source stream and write to the destination stream dstText.Write(srcText.ReadToEnd()); } // Close both streams } private static Encoding GetEncoding(String s) { try { // Assume the user passed an integer identifying a code page return Encoding.GetEncoding(Int32.Parse(s)); } catch (FormatException) { // The user didn't pass an integer code page value } // Assume the user passed a string identifying a code page return Encoding.GetEncoding(s); } } /// <summary> /// Base64 编码和解码 /// </summary> internal static class Base64Encoding { public static void Go() { // 获取一组10个随机生成的字节 Byte[] bytes = new Byte[10]; new Random().NextBytes(bytes); // 显示字节 Console.WriteLine(BitConverter.ToString(bytes)); // 将字节解码成Base-64字节串,并显示字符串 String s = Convert.ToBase64String(bytes); Console.WriteLine(s); // 讲Base-64字符串编码回字节,变显示字节 bytes = Convert.FromBase64String(s); Console.WriteLine(BitConverter.ToString(bytes)); } } /// <summary> /// 安全字符串,主要防止 机密数据在内存中被破解! /// </summary> internal static class UsingSecureString { public static void Go() { using (SecureString ss = new SecureString()) { Console.Write("Please enter password: "); while (true) { ConsoleKeyInfo cki = Console.ReadKey(true); if (cki.Key == ConsoleKey.Enter) break; // 将密码字符附加到SecureString中 ss.AppendChar(cki.KeyChar); Console.Write("*"); } Console.WriteLine(); // 密码已输入,处于演示的目的显示它 //DisplaySecureString(ss); } // 'using'之后, SecureString 被 Disposed; 内存中无敏感数据 } // 这个方法是不安全的,因为它要访问非托管存存 // private unsafe static void DisplaySecureString(SecureString ss) //{ // Char* pc = null; // try // { // // 将 SecureString 解密到一个非托管内存缓冲区中 // pc = (Char*)Marshal.SecureStringToCoTaskMemUnicode(ss); // // 访问包含已解密的SecureString的非托管内存缓冲区 // // // for (Int32 index = 0; pc[index] != 0; index++) // Console.Write(pc[index]); // } // finally // { // // 确保清零变释放包含已解密SecureString字符的非托管内存缓冲区 // if (pc != null) // Marshal.ZeroFreeCoTaskMemUnicode((IntPtr)pc); // } // } }