.Net学习难点讨论系列6 - .Net中对字符串处理的方法
此文章在aierong 的http://www.cnblogs.com/aierong/archive/2005/04/26/145617.html基础上稍加改动。感谢原作者。
.Net提供了将数值、枚举或日期时间等数据类型表示为字符串的方法(依赖于给ToString()方法传入参数),也提供了(包括自定义解析过程)将字符串表示为某种类型的方法(类/对象名.Parse(string))。
格式化由格式说明符字符的字符串控制,该字符串指示如何表示基类型值;或者怎样将一个字符串解释为某个类型。
例如,格式说明符指示是否应该用科学记数法来表示格式化的数字;格式字符"C",表示货币格式等。(参考附录表格)
同时.NET Framework还使用区域性设置,以便用适合于特定区域性的形式表示基类型。
我们可以提供自定义的区域性设置,或者使用与当前线程关联的默认区域性设置。
例如,格式化货币类型的时候,区域性设置指定用于货币符号;格式化时间时根据区域设置来将一个字符串解释为DateTime型(DateTime.ParseExact()方法)。
本文主要介绍字符串格式控制
要是我们想拥有自己定义的格式化,.NET Framework也允许我们定义自己格式化方案和自定义区域性设置。例如:我想格式字符"MyFormat",来说明我自定义的格式,即在字符前加三个***,下文有代码示例。
提示:
关于数字格式字符串,可以参考类
System.Globalization.NumberFormatInfo
关于日期与时间格式字符串,可以参考类
System.Globalization.DateTimeFormatInfo
一个类要想实现格式化字符串输出需要实现Iformattable接口,先看看IFormattable接口的原型:
1 public interface IFormattable 2 { 3 string ToString(string format, IFormatProvider formatProvider); 4 }
参数说明:
- format: 指定要使用的格式的 String,当为空引用时,表示使用为IFormattable实现的类型定义的默认格式。
- formatProvider: 用于格式化该值的 IFormatProvider,当为空引用时,从操作系统的当前区域设置中获取格式信息的。
一些基本的值类型实现了该接口,例如: Int32 ,UInt32 , DateTime ,Guid ,类Enum。
其中的IFormatProvider接口的原型
1 public interface IFormatProvider 2 { 3 object GetFormat(Type formatType); 4 }
参数说明:
- formatType: 一个对象,它指定要获取的格式对象的类型
NumberFormatInfo、DateTimeFormatInfo和CultureInfo实现IFormatProvider接口。
- NumberFormatInfo: 提供数字格式信息,如用于小数分隔符和千位分隔符的字符,以及货币值中货币符号的拼写和位置。
- DateTimeFormatInfo: 提供与日期相关和与时间相关的格式信息,如日期模式中月、日和年的位置。
- CultureInfo: 包含特定区域性中的默认格式信息,其中包括数字格式信息以及与日期相关和与时间相关的格式信息。
再看看ICustomFormatter接口的原型:
1 public interface ICustomFormatter 2 { 3 string Format(string format, object arg, IFormatProvider formatProvider); 4 }
参数说明:
- format: 包含格式规范的格式字符串。为空时 ,将使用默认格式规范。
- arg: 要格式化的对象。其为空引用时,引发异常。
- formatProvider : 一个IFormatProvider对象,它提供有关当前实例的格式信息。为空时,则忽略该参数。
代码示例:格式字符串"MyFormat",在字符前加三个***。
1 using System; 2 3 public class MyClass : IFormattable 4 { 5 Double d; 6 7 public MyClass(Double d) 8 { 9 this.d = d; 10 } 11 12 public string ToString(string format, IFormatProvider formatProvider) 13 { 14 return (format == "MyFormat") ? 15 "***" + d.ToString(formatProvider) 16 : d.ToString(format, formatProvider); 17 } 18 } 19 20 class Program 21 { 22 public static void Main() 23 { 24 System.Globalization.CultureInfo culture = null; 25 26 MyClass myClass = new MyClass(5); 27 28 //当IFormatProvider为空时,调用的是当前线程关联的文化信息 29 Console.WriteLine("显示当前线程关联的文化信息(中国)货币格式:{0}", myClass.ToString("C", null)); 30 31 culture = System.Globalization.CultureInfo.CurrentCulture; 32 Console.WriteLine("显示当前系统默认货币格式:{0}", myClass.ToString("C", culture)); 33 34 culture = new System.Globalization.CultureInfo("zh-HK"); 35 Console.WriteLine("显示香港特别行政区货币格式:{0}", myClass.ToString("C", culture)); 36 37 Console.WriteLine("显示我自己定义的货币格式:{0}", myClass.ToString("MyFormat", null)); 38 39 Console.ReadLine(); 40 } 41 }
输出结果:
显示中国货币格式:¥5.00
显示当前系统默认货币格式:¥5.0
显示香港特别行政区货币格式:HK$
显示我自己定义的货币格式:***5
以上示例中CultureInfo类的对象作为IFormatProvider类型的参数传入。自定义中调用了Double对象的ToString方法,因为Double对象也实现了IFormattable接口。
如果希望自定义格式化能在多个不同类使用,那么实现我们应该定义一个实现ICustomFormatter接口的类:
1 using System; 2 3 public class MyBaseFormat : ICustomFormatter, IFormatProvider 4 { 5 //如果format Type与当前实例类型相同,则为当前实例,否则为空引用 6 public object GetFormat(Type format) 7 { 8 if (format == typeof(ICustomFormatter)) 9 return this; 10 return null; 11 } 12 13 //实现Format方法说明: 14 //如果您的格式方法不支持格式,则确定正在设置格式的对象是否实现IFormattable接口。 15 //如果实现,请调用对象的接口上的IFormattable.ToString方法。 16 //否则,调用对象基类默认的Object.ToString方法。 17 public string Format(string format, object arg, IFormatProvider provider) 18 { 19 if (format == null) 20 { 21 if (arg is IFormattable) 22 return ((IFormattable)arg).ToString(format, provider); 23 return arg.ToString(); 24 } 25 else 26 { 27 if (format == "MyBaseFormat") 28 { 29 return "***" + arg.ToString(); 30 } 31 else 32 { 33 if (arg is IFormattable) 34 return ((IFormattable)arg).ToString(format, provider); 35 return arg.ToString(); 36 } 37 } 38 } 39 } 40 41 class Program 42 { 43 public static void Main() 44 { 45 string printString = String.Empty; 46 int i = 100; 47 MyBaseFormat myBaseFormat = new MyBaseFormat(); 48 49 printString = string.Format(myBaseFormat, "显示正常格式:{0}", i); 50 Console.WriteLine(printString); 51 printString = string.Format(myBaseFormat, "显示正常格式:{0:C}", i); 52 Console.WriteLine(printString); 53 printString = string.Format(myBaseFormat, "显示自定义格式{0:MyBaseFormat}", i); 54 Console.WriteLine(printString); 55 56 Console.ReadLine(); 57 } 58 }
输出如下:
显示正常格式:100
显示正常格式:¥100.00
显示自定义格式***100
总结:
1.如果需要您自己的格式化包含在某个类上,在该类上实现IFormattable接口。
2.如果希望自定义格式化并使它可供多个不同类使用,那么实现 ICustomFormatter接口。
下面的函数是一个在网上找的的使用IFormattable的例子:
1 using System; 2 3 /// <summary> 4 /// "点"类的定义。 5 /// </summary> 6 public class Point : IFormattable 7 { 8 /// <summary> 9 /// 点类的横纵坐标。 10 /// </summary> 11 private int m_x, m_y; 12 13 public Point(int x, int y) 14 { 15 m_x = x; 16 m_y = y; 17 } 18 19 #region IFormattable 成员 20 /// <summary> 21 /// 用于生成格式字符串的函数。 22 /// </summary> 23 /// <param name="format">格式字符串。</param> 24 /// <param name="formatProvider">区域格式信息对象。</param> 25 /// <returns></returns> 26 public string ToString(string format, IFormatProvider formatProvider) 27 { 28 string retString; 29 try 30 { 31 //判断格式字符串。 32 switch (format.ToUpper()) 33 { 34 //自定义的通用格式。 35 //"点"对象的字符串格式为:"(十进制数字,十进制数字)"。 36 case "G": 37 retString = string.Format(formatProvider, "({0},{1})", m_x, m_y); 38 break; 39 //自定义的标准格式。 40 //"点"对象的字符串格式为:"<十进制数字,十进制数字>"。 41 case "S": 42 retString = string.Format(formatProvider, "<{0},{1}>", m_x, m_y); 43 break; 44 //自定义的默认格式。 45 //"点"对象的字符串格式为:"(十六进制数字,十六进制数字)"。 46 default: 47 retString = string.Format(formatProvider, "({0:X},{1:X})", m_x, m_y); 48 break; 49 } 50 } 51 catch (NullReferenceException) 52 { 53 //格式字符串为空,返回通用格式。 54 retString = string.Format(formatProvider, "({0},{1})", m_x, m_y); 55 } 56 return retString; 57 } 58 #endregion 59 } 60 /// <summary> 61 /// Test 的摘要说明。 62 /// </summary> 63 public class Test 64 { 65 public static void Main() 66 { 67 //定义一个点。 68 Point p = new Point(13, 10); 69 //打印默认格式的点。 70 Console.WriteLine("{0}", p); 71 //打印标准格式的点。 72 Console.WriteLine("{0:S}", p); 73 74 Console.ReadLine(); 75 } 76 }
程序输出如下:
(13,10)
<13,10>
注意:如果不实现IFormattable接口也可以用string.Format这些方法打印自定义类的对象,但string.Format方法只是调用object.ToString方法将类名打印出来。
下面是string.Format这些方法调用ToString的处理顺序:
1.如果要格式化的对象的值是 null,则返回空字符串 ("")。
2.如果要格式化的对象所属的类实现了 ICustomFormatter 接口,则调用ICustomFormatter.Format 方法。
3.如果前面的ICustomFormatter.Format 方法未调用,并且该类实现了 IFormattable 接口,则调用IFormattable.ToString 方法。
4.如果前面的步骤未格式化类型,则调用该类型的ToString方法(从 Object 类继承而来)。
然而,只有实现了IFormattable或ICustomFormatter这些接口才能识别我们自己定义的格式字符串,打印出我们想要的结果。
附录:
C#格式化数值结果表
字符 |
说明 |
示例 |
输出 |
C |
货币 |
string.Format("{0:C3}", 2) |
$2.000 |
D |
十进制 |
string.Format("{0:D3}", 2) |
002 |
E |
科学计数法 |
string.Format("{0:E}", 1.20E+001) |
1.20E+001 |
G |
常规 |
string.Format("{0:G}", 2) |
2 |
N |
用分号隔开的数字 |
string.Format("{0:N}", 250000) |
250,000.00 |
X |
十六进制 |
string.Format("{0:X000}", 12) |
C |
string.Format("{0:000.000}", 12.2) |
012.200 |
string.Format()控制字符串缩进小技巧:
Sample |
Generates |
String.Format("->{1,10}<-", "Hello"); |
-> Hello<- |
String.Format("->{1,-10}<-", "Hello"); |
->Hello <- |
最后还有一些需要介绍的小技巧:
C# 中String.Format接收的标记,可以以任意顺序使用,且可以在格式字符串中替换任意次。
下面的例子的很好的解释了上文所述:
1 Console.WriteLine("The output is {1}, {0} and {1}.", "3", "6");
程序输出为:
The output is 6, 3 and 6.
具体格式项的语法如下:{index, alignment:format}
- index为索引号,这是我们最常见的也是必须的。
- alignment,可选项,表示格式化后的字符串占的长度,及左对齐还是右对齐(整数或负数),如果指定的长度比字符串短,则对齐设置会被忽略
如:
1 string str = "cnblogs"; 2 Console.WriteLine("|{0,10}|",str); 3 Console.WriteLine("|{0,-10}|",str);
对齐效果如下:
| cnblogs|
|cnblogs |
format为格式组件,用于将对象格式化为想要的字符串。