.Net学习难点讨论系列6 - .Net中对字符串处理的方法
2011-05-24 21:03
459 查看
此文章在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
接口的原型:
public interface IFormattable
{
// Methods
string ToString(string format, IFormatProvider formatProvider);
}
参数说明:
format: 指定要使用的格式的 String,当为空引用时,表示使用为IFormattable实现的类型定义的默认格式。
formatProvider: 用于格式化该值的 IFormatProvider,当为空引用时,从操作系统的当前区域设置中获取格式信息的。
一些基本的值类型实现了该接口,例如: Int32 ,UInt32 , DateTime ,Guid ,类Enum。
其中的IFormatProvider
接口的原型
public interface IFormatProvider
{
// Methods
object GetFormat(Type formatType);
}
参数说明:
formatType: 一个对象,它指定要获取的格式对象的类型
NumberFormatInfo、DateTimeFormatInfo和CultureInfo实现IFormatProvider接口。
NumberFormatInfo: 提供数字格式信息,如用于小数分隔符和千位分隔符的字符,以及货币值中货币符号的拼写和位置。
DateTimeFormatInfo: 提供与日期相关和与时间相关的格式信息,如日期模式中月、日和年的位置。
CultureInfo: 包含特定区域性中的默认格式信息,其中包括数字格式信息以及与日期相关和与时间相关的格式信息。
再看看ICustomFormatter
接口的原型:
public interface ICustomFormatter
{
// Methods
string Format(string format, object arg, IFormatProvider formatProvider);
}
参数说明:
format: 包含格式规范的格式字符串。为空时 ,将使用默认格式规范。
arg: 要格式化的对象。其为空引用时,引发异常。
formatProvider : 一个IFormatProvider对象,它提供有关当前实例的格式信息。为空时,则忽略该参数。
代码示例:格式字符串"MyFormat",在字符前加三个***。
using
System;
public
class
MyClass
: System.IFormattable
{
Double
d;
public
MyClass(Double
d)
{
this
.d = d;
}
public
string
ToString(string
format, IFormatProvider
formatProvider)
{
return
(format == "MyFormat"
) ? "***"
+ d.ToString(formatProvider) : d.ToString(format, formatProvider);
}
}
class
Program
{
public
static
void
Main()
{
System.Globalization.CultureInfo
culture=null
;
MyClass
myClass = new
MyClass
(5);
//
当
IFormatProvider
为空时
,
调用的是当前线程关联的文化信息
Console
.WriteLine("
显示中国货币格式
:{0}"
, myClass.ToString("C"
, null
));
culture = System.Globalization.CultureInfo
.CurrentCulture;
Console
.WriteLine("
显示当前系统默认货币格式
:{0}"
, myClass.ToString("C"
, culture));
culture = new
System.Globalization.CultureInfo
("zh-HK"
);
Console
.WriteLine("
显示香港特别行政区货币格式
:{0}"
, myClass.ToString("C"
, culture));
Console
.WriteLine("
显示我自己定义的货币格式
:{0}"
, myClass.ToString("MyFormat"
, null
));
Console
.ReadLine();
}
}
输出结果:
显示中国货币格式:¥5.00
显示当前系统默认货币格式:¥5.0
显示香港特别行政区货币格式:HK$
显示我自己定义的货币格式:***5
以上示例中CultureInfo类的对象作为IFormatProvider类型的参数传入。自定义中调用了Double对象的ToString方法,因为Double对象也实现了IFormattable接口。
如果希望自定义格式化能在多个不同类使用,那么实现我们应该定义一个实现ICustomFormatter接口的类:
public
class
MyBaseFormat
: System.ICustomFormatter
, System.IFormatProvider
{
//
如果
format Type
与当前实例类型相同,则为当前实例,否则为空引用
public
object
GetFormat(Type
format)
{
if
(format == typeof
(ICustomFormatter
))
return
this
;
return
null
;
}
//
实现
Format
方法说明
:
//
如果您的格式方法不支持格式,则确定正在设置格式的对象是否实现
IFormattable
接口。
//
如果实现,请调用该接口的
IFormattable.ToString
方法。
//
否则,调用基础对象的默认
Object.ToString
方法。
public
string
Format(string
format, object
arg, IFormatProvider
provider)
{
if
(format == null
)
{
if
(arg is
IFormattable
)
return
((IFormattable
)arg).ToString(format, provider);
return
arg.ToString();
}
else
{
if
(format == "MyBaseFormat"
)
{
return
"***"
+ arg.ToString();
}
else
{
if
(arg is
IFormattable
)
return
((IFormattable
)arg).ToString(format, provider);
return
arg.ToString();
}
}
}
}
class
Program
{
public
static
void
Main()
{
string
printString = String
.Empty;
int
i = 100;
MyBaseFormat
myBaseFormat = new
MyBaseFormat
();
printString = string
.Format(myBaseFormat, "
显示正常格式
:{0}"
, i);
Console
.WriteLine(printString);
printString = string
.Format(myBaseFormat, "
显示正常格式
:{0:C}"
, i);
Console
.WriteLine(printString);
printString = string
.Format(myBaseFormat, "
显示自定义格式
{0:MyBaseFormat}"
, i);
Console
.WriteLine(printString);
Console
.ReadLine();
}
}
输出如下:
显示正常格式:100
显示正常格式:¥100.00
显示自定义格式***100
总结:
1.如果需要您自己的格式化包含在某个类上,在该类上实现IFormattable接口。
2.如果希望自定义格式化并使它可供多个不同类使用,那么实现 ICustomFormatter接口。
下面的函数是一个在网上找的的使用IFormattable的例子:
using
System;
///
<summary>
///
"
点
"
类的定义。
///
</summary>
public
class
Point
: System.IFormattable
{
///
<summary>
///
点类的横纵坐标。
///
</summary>
private
int
m_x, m_y;
public
Point(int
x, int
y)
{
m_x = x;
m_y = y;
}
#region
IFormattable
成员
///
<summary>
///
用于生成格式字符串的函数。
///
</summary>
///
<param name="format">
格式字符串。
</param>
///
<param name="formatProvider">
区域格式信息对象。
</param>
///
<returns></returns>
public
string
ToString(string
format, IFormatProvider
formatProvider)
{
string
retString;
try
{
//
判断格式字符串。
switch
(format.ToUpper())
{
case
"G"
: //
自定义的通用格式。
retString = string
.Format(formatProvider, "({0},{1})"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"(
十进制数字,十进制数字
)"
。
break
;
case
"S"
: //
自定义的标准格式。
retString = string
.Format(formatProvider, "<{0},{1}>"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"<
十进制数字,十进制数字
>"
。
break
;
default
: //
自定义的默认格式。
retString = string
.Format(formatProvider, "({0:X},{1:X})"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"(
十六进制数字,十六进制数字
)"
。
break
;
}
}
catch
(System.NullReferenceException
)
{
//
格式字符串为空,返回通用格式。
retString = string
.Format(formatProvider, "({0},{1})"
, m_x, m_y);
}
return
retString;
}
#endregion
}
///
<summary>
///
Test
的摘要说明。
///
</summary>
public
class
Test
{
public
static
void
Main()
{
//
定义一个点。
Point
p = new
Point
(13, 10);
//
打印默认格式的点。
Console
.WriteLine("{0}"
, p);
//
打印标准格式的点。
Console
.WriteLine("{0:S}"
, p);
/*
*
输出结果:
(13,10)
* <13,10>
*/
Console
.ReadLine();
}
}
注意:如果不实现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#
格式化数值结果表
string.Format()
控制字符串缩进小技巧:
的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
接口的原型:
public interface IFormattable
{
// Methods
string ToString(string format, IFormatProvider formatProvider);
}
参数说明:
format: 指定要使用的格式的 String,当为空引用时,表示使用为IFormattable实现的类型定义的默认格式。
formatProvider: 用于格式化该值的 IFormatProvider,当为空引用时,从操作系统的当前区域设置中获取格式信息的。
一些基本的值类型实现了该接口,例如: Int32 ,UInt32 , DateTime ,Guid ,类Enum。
其中的IFormatProvider
接口的原型
public interface IFormatProvider
{
// Methods
object GetFormat(Type formatType);
}
参数说明:
formatType: 一个对象,它指定要获取的格式对象的类型
NumberFormatInfo、DateTimeFormatInfo和CultureInfo实现IFormatProvider接口。
NumberFormatInfo: 提供数字格式信息,如用于小数分隔符和千位分隔符的字符,以及货币值中货币符号的拼写和位置。
DateTimeFormatInfo: 提供与日期相关和与时间相关的格式信息,如日期模式中月、日和年的位置。
CultureInfo: 包含特定区域性中的默认格式信息,其中包括数字格式信息以及与日期相关和与时间相关的格式信息。
再看看ICustomFormatter
接口的原型:
public interface ICustomFormatter
{
// Methods
string Format(string format, object arg, IFormatProvider formatProvider);
}
参数说明:
format: 包含格式规范的格式字符串。为空时 ,将使用默认格式规范。
arg: 要格式化的对象。其为空引用时,引发异常。
formatProvider : 一个IFormatProvider对象,它提供有关当前实例的格式信息。为空时,则忽略该参数。
代码示例:格式字符串"MyFormat",在字符前加三个***。
using
System;
public
class
MyClass
: System.IFormattable
{
Double
d;
public
MyClass(Double
d)
{
this
.d = d;
}
public
string
ToString(string
format, IFormatProvider
formatProvider)
{
return
(format == "MyFormat"
) ? "***"
+ d.ToString(formatProvider) : d.ToString(format, formatProvider);
}
}
class
Program
{
public
static
void
Main()
{
System.Globalization.CultureInfo
culture=null
;
MyClass
myClass = new
MyClass
(5);
//
当
IFormatProvider
为空时
,
调用的是当前线程关联的文化信息
Console
.WriteLine("
显示中国货币格式
:{0}"
, myClass.ToString("C"
, null
));
culture = System.Globalization.CultureInfo
.CurrentCulture;
Console
.WriteLine("
显示当前系统默认货币格式
:{0}"
, myClass.ToString("C"
, culture));
culture = new
System.Globalization.CultureInfo
("zh-HK"
);
Console
.WriteLine("
显示香港特别行政区货币格式
:{0}"
, myClass.ToString("C"
, culture));
Console
.WriteLine("
显示我自己定义的货币格式
:{0}"
, myClass.ToString("MyFormat"
, null
));
Console
.ReadLine();
}
}
输出结果:
显示中国货币格式:¥5.00
显示当前系统默认货币格式:¥5.0
显示香港特别行政区货币格式:HK$
显示我自己定义的货币格式:***5
以上示例中CultureInfo类的对象作为IFormatProvider类型的参数传入。自定义中调用了Double对象的ToString方法,因为Double对象也实现了IFormattable接口。
如果希望自定义格式化能在多个不同类使用,那么实现我们应该定义一个实现ICustomFormatter接口的类:
public
class
MyBaseFormat
: System.ICustomFormatter
, System.IFormatProvider
{
//
如果
format Type
与当前实例类型相同,则为当前实例,否则为空引用
public
object
GetFormat(Type
format)
{
if
(format == typeof
(ICustomFormatter
))
return
this
;
return
null
;
}
//
实现
Format
方法说明
:
//
如果您的格式方法不支持格式,则确定正在设置格式的对象是否实现
IFormattable
接口。
//
如果实现,请调用该接口的
IFormattable.ToString
方法。
//
否则,调用基础对象的默认
Object.ToString
方法。
public
string
Format(string
format, object
arg, IFormatProvider
provider)
{
if
(format == null
)
{
if
(arg is
IFormattable
)
return
((IFormattable
)arg).ToString(format, provider);
return
arg.ToString();
}
else
{
if
(format == "MyBaseFormat"
)
{
return
"***"
+ arg.ToString();
}
else
{
if
(arg is
IFormattable
)
return
((IFormattable
)arg).ToString(format, provider);
return
arg.ToString();
}
}
}
}
class
Program
{
public
static
void
Main()
{
string
printString = String
.Empty;
int
i = 100;
MyBaseFormat
myBaseFormat = new
MyBaseFormat
();
printString = string
.Format(myBaseFormat, "
显示正常格式
:{0}"
, i);
Console
.WriteLine(printString);
printString = string
.Format(myBaseFormat, "
显示正常格式
:{0:C}"
, i);
Console
.WriteLine(printString);
printString = string
.Format(myBaseFormat, "
显示自定义格式
{0:MyBaseFormat}"
, i);
Console
.WriteLine(printString);
Console
.ReadLine();
}
}
输出如下:
显示正常格式:100
显示正常格式:¥100.00
显示自定义格式***100
总结:
1.如果需要您自己的格式化包含在某个类上,在该类上实现IFormattable接口。
2.如果希望自定义格式化并使它可供多个不同类使用,那么实现 ICustomFormatter接口。
下面的函数是一个在网上找的的使用IFormattable的例子:
using
System;
///
<summary>
///
"
点
"
类的定义。
///
</summary>
public
class
Point
: System.IFormattable
{
///
<summary>
///
点类的横纵坐标。
///
</summary>
private
int
m_x, m_y;
public
Point(int
x, int
y)
{
m_x = x;
m_y = y;
}
#region
IFormattable
成员
///
<summary>
///
用于生成格式字符串的函数。
///
</summary>
///
<param name="format">
格式字符串。
</param>
///
<param name="formatProvider">
区域格式信息对象。
</param>
///
<returns></returns>
public
string
ToString(string
format, IFormatProvider
formatProvider)
{
string
retString;
try
{
//
判断格式字符串。
switch
(format.ToUpper())
{
case
"G"
: //
自定义的通用格式。
retString = string
.Format(formatProvider, "({0},{1})"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"(
十进制数字,十进制数字
)"
。
break
;
case
"S"
: //
自定义的标准格式。
retString = string
.Format(formatProvider, "<{0},{1}>"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"<
十进制数字,十进制数字
>"
。
break
;
default
: //
自定义的默认格式。
retString = string
.Format(formatProvider, "({0:X},{1:X})"
, m_x, m_y);
//"
点
"
对象的字符串格式为:
"(
十六进制数字,十六进制数字
)"
。
break
;
}
}
catch
(System.NullReferenceException
)
{
//
格式字符串为空,返回通用格式。
retString = string
.Format(formatProvider, "({0},{1})"
, m_x, m_y);
}
return
retString;
}
#endregion
}
///
<summary>
///
Test
的摘要说明。
///
</summary>
public
class
Test
{
public
static
void
Main()
{
//
定义一个点。
Point
p = new
Point
(13, 10);
//
打印默认格式的点。
Console
.WriteLine("{0}"
, p);
//
打印标准格式的点。
Console
.WriteLine("{0:S}"
, p);
/*
*
输出结果:
(13,10)
* <13,10>
*/
Console
.ReadLine();
}
}
注意:如果不实现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 <- |
相关文章推荐
- .Net学习难点讨论系列6 - .Net中对字符串处理的方法
- .Net学习难点讨论系列6 - .Net中对字符串处理的方法
- .Net学习难点讨论系列9 -泛型类型参数的约束 泛型方法
- .Net学习难点讨论系列10 - 匿名方法,Lambda表达式及其对局部变量的影响
- .Net学习难点讨论系列10 - 匿名方法,Lambda表达式及其对局部变量的影响
- .Net学习难点讨论系列1 – 委托与事件之事件
- .Net学习难点讨论系列2 – 细说C#中new关键字与多态
- .Net学习难点讨论系列3 – .线程同步问题之一
- .Net学习难点讨论系列17
- .Net学习难点讨论系列12 - 垃圾回收
- .Net学习难点讨论系列4 – .Net委托类型
- .Net学习难点讨论系列4 – .Net委托类型
- .Net学习难点讨论系列5 – 线程同步问题之二
- .Net学习难点讨论系列7 - .NET委托补充
- .Net学习难点讨论系列2 – 细说C#中new关键字与多态
- .Net学习难点讨论系列3 – .线程同步问题之一
- .Net学习难点讨论系列8 - 泛型字典类比较
- .Net学习难点讨论系列1 – 委托与事件之事件
- .Net学习难点讨论系列17 - 线程本地变量的使用
- .Net学习难点讨论系列8 - 泛型字典类比较