`

11章 转换

阅读更多

说明:本文翻译自《TangoRefMan_Sep_1_2008》

      

由于本人是编程初学者,对很多程序设计概念不是非常熟悉,编程经验不多,再加上英语水平不高,翻译纯属一个D语言爱好者实验之作,很多错误在所难免,还请读者见谅。另外,如果你发现本文有不当和错误之处,还请多提宝贵意见。  


11章  转换


在像D语言这样的静态语言中,文本转换是必需的,Tango提供给我们一些简单的方法转换文本,并包含一个综合性的格式化框架,它吸取了.net框架的精华。这个框架也是Tango的场所(locale)支持的基础。
转换模块在Tango的tango.text.convert包中(不包括场所支持的需要)。
本章将开始介绍tango.text.convert的两个主要部分:从基本类型转换到文本和从文本转换到基本类型与及文本的格式化。之后,将给出每个模块更详细的描述。
第一节  在文本和数值间转换
具体的转换通过各个转换器,多数的转换器执行从文本翻译到数值或相反的操作。每个转换器都有两个能用方法:
parse  从文本表示转换到某种类型。
format 从某种类型转换到文本表示。
format
所有的format函数需要有一个输出缓冲器作为第一个参数,这样避免堆活动,并且指示转换器你将要输出到哪一种文本编码(char[],wchar[]还是dchar[])。输入被转换的数据通常用作第二个参数,输出的文本结果是所提供的输出缓冲流的一个切片。用户利用返回值代替原始缓冲器,尽管内存是相同的(返回值是正确大小的一个切片,不是整个输出缓冲器)。
在这种情况下,有两种通用方法提供缓冲器。如果结果能存在栈上可以这样做:
char[10] output ;//转换器使用.length作为最大尺寸
auto  result=format(output,15);//格式化数字15
如果结果需要放置在堆上,如排除其他一些函数,最简单的解决方法是:
auto  result = format (new char[10],15);
两种方法都可以,但后一种形式具自说明性且更为简洁。
每个format方法被模块操作用于输出自然的D字符数组:char[],wchar[],dchar[] 。它们的通常格式为:
T[] format(T[] dst,V x)
T可以是char,wchar或dchar类型,V是要转换的基本类型,上面的形式只说明性的,一些模板有更多选项。
不同的format版本可能有附加的参数用于具体说明关于要转换的类型的格式细节。
parse
parse函数用一个说明编码的字符串作为它的第一个参数,返回一个转换后的值。
和format类似,parse被模块操作处理自然的D文本类型输入数组(char[],wchar[],dchar[] ),通常形式为:
V parse (T[])
其中的T是char,wchar或dchar类型,V是字符串转换成的数值类型。
像format一样,不同版本的parse有可以附加参数提供用于解析输入字符串的相关细节。
转换器提供一部分方便的包装,如下面的形式:
toString,toString16,toString32
这些函数把输入的数值类型转换成像函数名一样的特定字符串类型。这些函数不需要一个安放结果的预分配数组。模板形式类似于format,但没有结果参数。
T []  toString××(V x )

 

 

toType
给定一个输入字符串,多数模块有一个函数产生和函数名一样的特定返回值,输入的字符串必须能够正确解析。
模块形式为: V toTypd (T[])
避免符号冲突
转换模块由大多数独立式函数组成,并且许多有通用名字,如parse,format等等,为避免编译时符号冲突,也为了避免导入其他库时引起意外冲突,建议实践中使用重命引入给导入函数创建一个名字空间,使用Integer模块的一个例子如下:
import Integer = tango.text.convert.Integer;
auto I =Integer.parse(‘32767’);

Integer 模块
tango.text.convert.Integer模块有一些函数帮助我们从字符串类型转换成整数类型,或执行相反操作。这些改变从快速和脏的方法到更综合化的安全的方法,在下面的例子中,一个默认的parse和format用法被展示:
auto value = Integer.parse(“0xff005500“);
auto text= Integer.format(new char[32],12345L);
parse 能使用两个附加参数,一个uint型参数提供要被转换的数制(radix of the number),一个指向uint的ate参数限定被解析的字符串长度。注意:如果字符串自己有明确的数制,提供的radix参数将会被忽略。
支持的radix变量
详细说明 Radix 示例
B或b 2(binary,即二进制) 0b10101
O或o 8(octal即二进制) 0o654
X或x 16(hexadecimal即二进制) 0xDEADBEEF
无 10(decimal,即二进制) 150
format也有两个附加参数,即一个标志使用什么格式,一个标志附加的修改
格式类型标志
格式标志 描述
Format.Unsigned 格式化为无符号十进制数
Format.Signed 格式化为有符号十进制数(默认)
Format.Octal 格式化为一个八进制数
Format.Hex 格式化为小写十六进制数
Fornat.HexUpper 格式化为大写十六进制数
Format.Binary 格式化为一个二进制数
附加修改形式为
修改标志 描述
Flags.None(默认) 不修改
Flags.Prefix 添加具体数制前缀
Flags.Plus 正数前添加“+”号
Flags.Space 正数前添加一个空格
Flags.Zero 从左起填充“0”
下面是一个输出前缀为十六进制数的例子
auto text =Integer.format(new char[32],12345L,Format.HexUpper,Flags.Prefix)
toString,toString16,toString32也能使用format的格式标志和修改标志,但更为简单,它们不需要预分配输出数组。
toInt和toLong提供从字符串到整数值类型转换的方便包装,它们要求输入字符串必须全部可解析,同时,任意提供的radix在字符串将被推翻。如果输入字符串不能被完整解析将会抛出一个异常。
附加函数包括convert,它不查找输入字符串中的radix。trim会试图从字符串中提取任意的符号和radix,整理字符串的空格。
atoi和itoa用于快速从字符串转换到uint类型和从uint类型转换到字符串,后者将仅用于当输入已经知道有根据的情况。
Float
Tango.text.convert.Float模块提供给用户快速容易地转换浮点数(Float/duble/real)到字符串和从字符串转换到浮点数。下面 的例子是parse和format的默认用法:
auto  value = Float.parse(“3.145”);
auto  text = Float.format( new char[64],3.145);
parse仅有一个附加参数可以使用,一个指向一个uint型的ate参数控制字符串解析的长度到提供的结果。
format不同,有两个附加 参数,一个给十进制数用(默认为6),一个bool型指明格式是否为科学计数法表示(默认为false)。
toString,toString16,toString32可以使用format一样的参数,但不需要预分配的数组,它返回一个函数名指明的具体类型数组。
toDouble是从字符串转换到浮点数的最简单形式,返回一个double值。如果提供的输入不能完整解析,会抛出一个异常。
Layout(布局)
 Layout模板类有一个convert()方法可以用来动态格式化文本,并且被一些别的模块如Stdout 和 Sprint使用。
  一般说来,Layout工作要么调用sprint()要么调用convert()。opCall别名为convert。
  不同的是,convert 并堆分配结果,然而用户可以为结果提供一个缓冲器给sprint方法。
  在Format中的sprintf函数大体等价物是静态的Format.sprint 函数它要取得一个格式化字符串和一些参数,并且产生一个输出字符串。(这是一个超越sprintf的很好的改进,由于sprintf没有给你机会,你会溢出输出缓冲器)。
布局格式化字符串(Layouts format string)
语法和C#语法接近
例子:
Layout!(char) Layouter = new Layout!(char)();
int   nError = 12;
char  []  res =Layouter.format(“Error{} occurred.”,nError);//”Error 12 occurred.”
注意格式器的opCall影响使.format语法冗长,以下两个调用是等价的:
char []  res1 = Layouter(“Error{} occurred.”,nError);//”Error 12 occurred.”
char []  res2 = Layouter.format(“Error{} occurred.”,nError);//”Error 12 occurred.”
用简洁的.formatln()进行转换和添加一个新行。
利用D的metadata,格式器不需要格式字符串告之你要格式的数据类型。在上例中{}将会替换为nError的值,如果我们要具体说明用几位数字,是什么数制该如何办呢?
在{}中的文字有这个格式:
’{’ [ArgIndex][,Alignment][:FormatSpecifier]’}’
’{’ [参数索引][,对齐协定][:格式细节]’}’
参数索引指出使用第几个参数(从0数起)。如果没有参数索引,通常将用下一个参数,大多数时候,不需要使用它,只需要简单地使用{}就行了。如果要从一个文件中读取格式字符串,并处理不同的译文,参数索引就非常有用了。因为不同的语言翻译字符串可能在不同的地方,所以需要使用确切的参数索引值。另外,多次使用同一个参数出因参数索引而显得方便。
对齐协定,如果是正的,文字被右对齐,不足的字符位置填充空格,如果对齐协定是负的,则进行左对齐,如
Layouter("->{,10}<-'',"Hello");// ”->     Hello<-”
Layouter("->{,-10}<-'',"Hello");// ”->Hello     <-”
对齐协定不限定参数大小,它仅填充必要的空格,如
Layouter("->{,5}<-'',"HelloHello");// ”->HelloHello<-”
数字格式(即第三个可选项“格式细节”
格式 d x X B,b O,o
描述 十进制(默认) 小写十六进制 大写十六进制 二进制 八进制
格式字母后再加数字表示要用几位最少数字来表示,如下例:
Layouter(“{}”,123;   //”123”  默认十进制
Layouter(“{:d}”,123;   //”123”  十进制
Layouter(“0x{:x}”,123;   //  ”0x7b”  小写十六进制
Layouter(“{:4}”,123;   //”0x007b”  小写十六进制,最少4位
Layouter(“0x{:X}”,123;   //”0X7B”  大写十六进制
Layouter(“0o{:o}”,123;   //”0o173”  八进制
Layouter(“0b{:b}”,123;   //”0b1111011” 二进制
数组类型
Layout能格式数组类型
Int [] a = [123,456];         //动态数组
Ushort[3] b = [cast(ushort) 1,2,3];    //静态数组
Layouter (“{},a);   //           ”[123,456]”
Layouter (“{},b);   //   “[1,2,3]
Char[] [double] f ;
F[1.0] = “one”.dup;
F[3.14}= “PI”.dup;
Layouter (“{},f);   //   “{1.00=>one,3.14=>PI}”
数字格式和对齐协定可以应用到数组元素  map的情况下,数字格式和对齐协定也能应用。
如果要输出左大括号,就重复写两次,右大括号不用重复写。
使用Sprint或cstom sink(自定义搜索)。
Sprint成员函数超过format调用的好处是,没有堆活动(heap activity),Layout.sprint方法需要一个预分配的缓冲器。
警告:在多线程程序中,不要使用全局缓冲器,这样会使数据讹误。
如果需要的数据总量不太大,可使用一个基于栈的缓冲器:
char[250]  buf = void;  //仅获得一个缓冲器,没有初始化
char[] res = Layouter.sprint(buf,”My formatter number{}”,123);
也可以使用一个自己调用返回委托去消耗Layout数据。
void sink(char[] text){
//do something with text portion
Return text.Length;   //number of consumed chars
}
char[] res = Layouter(&sink,”My formatted number {}”,123);
Sprint
Sprint是一个格式前端,预分配一个输出缓冲器。Sprint接受标准C#风格格式,结果被缓冲器大小约束。Sprint作为Format相同风格的函数是:Printf函数家族的代替者。Sprint在tango.text.convert.Sprint模块中。
当你希望为 Logger(日志记录器)(或相类似的器)格式文字时,sprint是很方便的。它避免使用固定大小缓冲器进行转换期间产生堆活动Sprint类本身是stateful(独立的?),一个简单的实例不能被多个线程共享。
//创建一个Sprint实例
auto sprint = new Sprint!(char);
//写格式化的文字到控制台
Cout(sprint(“{0} is  {1} times {2}”,”julio”,32,5.68732));
如上例所见,Sprint可使用char,wchar,dchar进行模板实例化。
Utf
tango.text.convert.Utf模块包含所有的在各种通用编码(unicode)间互相转换的函数,包括ASCII子集。
toString,toString16,toString32分别返回char[],wchar[]和dchar[]。
例子:
auto utf8 = toString(“test”);
auto utf16 = toString16(“test”);
auto utf32 = toString32(“test”);
这些函数的完整原形为
T[] toStringⅩⅩ(U[] input, T[] output=null,uint* ate =null)
output参数用于用户想提供一个预分配空间给结果的情况,而ate参数提供给调用者将有几个字符会被处理。
UnicodeBom
tango.text.convert.UnicodeBom模块用于把内容编码成带BOM(字节序标志)的通用编码或从通用编码中解码。你可以间接地通过tango.io.UnicodeFile使用它,不过它直接使用也很方便。
通过检测最开始的少量特定部分字节,UnicodeBom可以自动检测文件的编码形式。了可以使用提供的常量Encoding.UTF_16BE,Encoding.UTF_32LE等等明确指定是什么编码方式。
举个例子,我们读和转化一wh带有BOM标志的文件内容到char[]数组并在控制台显示:
auto file =new File(“myfile.txt”);
auto bom = new UnicodeBom!(char)(Encoding.Unknown);
Stdout(bom.decode(file.read));
getEncodint和getSignature让用户获取关于BOM的信息,setup让用户设置(或重置)编码。
编码 标志 signature 描述
Encoding.Unknown N/A 完全未知编码
Encoding.UTF_8 N/A 预期UTF_8编码
Encoding.UTF_8N x”efbbbf” 明确设置为UTF_8N编码
Encoding.UTF_16 N/A 预期UTF_16编码
Encoding.UTF_16BE x”feff” 明确设置为UTF_16BE编码(大端)
Encoding.UTF_16LE x”fffe” 明确设置为UTF_16LE编码(小端)
Encoding.UTF_32 N/A 预期UTF_32编码
Encoding.UTF_32BE x”0000feff” 明确设置为UTF_32BE编码(大端)
Encoding.UTF_32LE x”fffe0000” 明确设置为UTF_32LE编码(小端)
encode和decode将会在不同编码间转换,取决于实例如何设置。encode把提供的内容编码成指定的unicodeBom类型,decode把输入数据按特定类型(或检测到的类型)解码成具体类型的数据。
TimeStamp(时间戳)
使用tango.text.convert.TimeStamp模块,HTML时间戳可以从字符串类型转换到ulong类型或从ulong类型转换到字符串类型。转换器会把任意的RFC1123、RFC850、asctime、Dostime或ISO-8601格式作为输入字符串,返回从1970年1月1日起的秒数,或相反地,转换从那天起的秒数到RFC1123时间(字符)串。
在下例中,parse和format的默认使用被展示。
auto date =”Sun,06 Nov 1994 08:49:37 GMT”;//RFC1123时间字符串
auto msSinceEpoch =TimeStamp.parse(date);
auto text = TimeStamp.format(new char[64],msEpoch);
parse可使用一个附加参数,一个指向uint类型的ate参数控制被解析的字符串长度,这个函数尝试与RFC1123、RFC850和asctime格式对比,如果都失败将返回InvalidEpoch(无效)值,toTime是一个更简单的封装,如果输入字符串不能被完整解析,将会抛出一个异常。
format没有附加参数,这和其它通用转换器模块不同,它把输入时间看作一个ulong值类型,toString,toString16,toString32封装这个函数,以免用户需要提供一个预分配缓冲器给结果。
要转换Dos time和ISO-8601格式,分别使用dostime和iso8601.随之还有rfc1123、rfc850和asctime返回元素在输入字符串中被解析的部分,结果值通过一个inout参数被提供。抽有这些函数的通用外形特征可看作
int fromTimeFormat(T[] src,inout ulong value)
fromFormat可以是上述五个函数中的任一种,输入源可以是char[],wchar[]或dchar[]中的任一种。
通用转换
Tango通过tango.util.Convert模块中的to函数支持通用值转换,这个函数允许你在任意类型间进行值保护转换。
如    real pi = to!(real)(“3.14159”);
上面的例子将把字符串值3.14159转换成最接近的等价实数类型值。有两种情况to函数转换会失败:
1.如果to不能找到在给定的两种类型间合适的转换器,它会流出一个编译时错误信息给你,如不能把一个虚数类型转换为一个整数类型,它们间是完全不相干的两个范畴。
2.如果to函数发现在运行时不能用目标类型描述给定的值,它将抛出一个Conversion Exception异常。例如,不能把字符串值“256”、“-1”或“que?”转换成ubyte类型,否则会抛出此异常。
下表是to函数支持的转换
目标类型 源类型
bool 整数型(0/!0)和字符串类型(”true”/”false”)
整数类型 bool、实数类型和字符串类型
实数类型 整数类型、字符串类型
虚数类型 复数类型
复数类型 整数类型、实数类型、虚数类型
字符串类型 bool、整数类型、实数类型
当然也可以在不同类型的数组间进行转换,不同类型的关联数组间转换。按顺序从一个数组T[]转换到数组S[],需要能够从每个T转换到每个S,要在关联数组Va[Ka]和Vb[Kb]间进行转换,需要能从每个Va转换到Vb,从每个Ka转换到Kb。
最后,to可以扩展到支持用户自定义的结构和类,这样做要在你自定义类型中定义适当的静态和实例成员函数。下表归纳了应包括的规则
目标 源 调用尝试
dst_type dst src_type src  src.toDstType(),src.to!(dst_type)(),dst_type.fromType(src),
dst_type.from!(src_type)(src)
dst_type dst[] src_type src src.toDstTypeArray()
dst_type dst src_type[] src dst_type.fromDstTypeArray(src)
dst_type[key_type] src_type src Src.toKeyTypeToDstTypeMap(0
char[],wchar[],
dchar[] src_type src src.toString(),src.toString16(),src.toString32()
dst_type  char[],wchar[],
dchar[] src dst_type..fromUtf8(src),dst_type..fromUtf16(src),dst_type..fromUtf32(src)
注意:在字符串转换情况下,如果合适的UTF编码不能直接支持,Tango将会转换到无论哪个可行的编码,然后翻译结果到期待的类型。也要注意,如果特定名称的方法没找到,to会落到通用的src.to!(dst_type)()和dst_type.from!(src_type)(src)调用上来。
这里是一个简单的用户自定义结构例子,招待一些转换。
struct Foo
{
real value;
int toint()
{
      Return to!(int)(value);
     }
static Foo fromReal!(real v)
     {
     return Foo(v);
     }
 T to(T))
     {
static if(is(T==iral))
retirm value*-1.0i;
else
static assert(false);
}
static Foo from(T)(T src)
   {
static if(is(T==iral))
return Foo(src*-1.0i);
else
static assert(false);
  }
}
下面的转换是有效的
to!(int)(Foo(42));  // ==42
to!(Foo)(3.14159);  // ==Foo(3.14159)
to!(char[])(Foo(123.456));  //==”123.456”c
to!(ireal)(Foo(456.789));   //==-456.789i
to!(Foo)(-789.123i);  //==Foo(789.123)

分享到:
评论
1 楼 hqs7636 2009-03-30  
感谢,辛苦!

相关推荐

    第11章AT89S51 DA、AD转换的接口.ppt

    《第11章 AT89S51 DA、AD转换的接口》主要讲解了AT89S51单片机如何与数字/模拟(D/A)转换器和模拟/数字(A/D)转换器进行接口设计,以及相关的转换原理和常用集成电路芯片的应用。 11.1 AT89S51单片机与D/A转换器的...

    数字电子技术基础课件:第十一章 数-模和模-数转换.ppt

    《数字电子技术基础课件:第十一章 数-模和模-数转换》 本课件主要探讨了数字电子技术中的重要组成部分——数模转换器(D/A转换器)和模数转换器(A/D转换器)的工作原理、类型以及性能比较。数模转换器能够将数字...

    数字电子技术基础:第十一章 数-模和模-数转换.ppt

    数模转换器(D/A转换器,DAC)将数字信号转换为模拟信号,这一过程是通过将数字量转换为与之成正比的模拟电压或电流。常见的D/A转换器类型包括权电阻网络型、倒梯形电阻网络型、权电流型、权电容型和开关树型。其中...

    第2章 C运算符和表达式-6赋值中的自动类型转换(下)1

    本章主要讨论了从一种数据类型向另一种数据类型赋值时可能出现的问题,特别是精度损失和安全性的议题。 首先,当从取值范围较小的数据类型(如`char`或`short`)赋值给范围较大的数据类型(如`int`、`float`或`...

    数字电路:第十一章 数-模和模-数转换.ppt

    《数字电路:第十一章 数-模和模-数转换》 在计算机系统和现代电子设备中,数模转换(D/A转换)和模数转换(A/D转换)扮演着至关重要的角色。本章深入探讨了这两种转换的基本原理和常见电路实现。 数模转换(D/A...

    数字电子技术基础讲义:第十一章 数-模(DA)和模-数(AD)转换.ppt

    《数字电子技术基础讲义:第十一章 数-模(DA)和模-数(AD)转换》 在数字电子技术中,数-模(D/A)和模-数(A/D)转换是两个至关重要的概念,它们在数据处理、信号处理以及控制系统的接口设计中扮演着核心角色。D...

    11.第十一章_数-模和模-数转换1

    第十一章主要讨论的是数-模(D/A)和模-数(A/D)转换器,这是数字信号处理系统中的关键组件,用于在数字和模拟信号之间进行转换。 数-模转换器(D/A Converter,DAC)是将数字信号转化为模拟信号的设备。D/A转换器...

    计算机结构与逻辑设计:第十一章 数-模和模-数转换.pdf

    计算机结构与逻辑设计课程中的第十一章内容主要讲解了数字与模拟信号之间的转换技术,包括数模转换(D/A转换器)和模数转换(A/D转换器)。本章内容为理解计算机内部信息处理过程以及与其他模拟系统交互时的信号转换...

    第11章spring-mvc默认转换器

    第11章spring-mvc默认转换器

    数字电路课件:第十一章 数-模和模-数转换.ppt

    《数字电路课件:第十一章 数-模和模-数转换》主要涵盖了数字电路中的重要组成部分——数模转换(D/A)和模数转换(A/D)。这些转换器在计算机与外部设备交互、数字测量以及数字控制系统中扮演着至关重要的角色。 1. ...

    第十一章a-d与d-a转换器接口2022优秀文档.ppt

    本章主要探讨了这两种转换器的接口设计和应用。 首先,D/A转换器(DAC)的主要任务是将数字量转化为模拟量。其关键参数包括分辨率、转换时间和精度。分辨率是指D/A转换器能够区分的最小电压差,通常与二进制位数...

    单片机:第11章 DA、AD转换的接口.ppt

    本章主要探讨了AT89S51单片机与DA(数字到模拟)转换器和AD(模拟到数字)转换器的接口设计。D/A转换器常用于将单片机处理后的数字信号转化为模拟信号输出,而A/D转换器则用于将传感器采集到的模拟信号转换为数字...

    中大单片机_第11章 MCS-51与DA转换器、AD转换器的接口.ppt

    第11章主要探讨了MCS-51单片机如何与D/A转换器和A/D转换器进行接口设计。MCS-51是广泛应用的8位微控制器,它经常需要处理模拟信号和数字信号之间的转换。A/D转换器(ADC)的作用是将模拟信号转化为数字信号,而D/A...

    数字电子技术基础:第11章_DA转换器.ppt

    【数字电子技术基础:第11章_DA转换器】这一章节主要探讨了数字信号与模拟信号之间的转换,即A/D转换器(模拟到数字转换器)和D/A转换器(数字到模拟转换器)的应用与原理。A/D转换器是数字系统与模拟世界交互的关键...

    ACCP8.0S2-Y2转换课程第2到11章上机课程素材(答案)

    在提供的【压缩包子文件的文件名称列表】"S2到Y2的转换"中,我们可以推测这包含了从第二章到第十一章的练习和答案,学员可以通过对比解答来检验自己的学习成果,加深对各个知识点的理解。这个资源对于那些正在学习或...

    数字电子技术基础:第十一章 数-模和模-数转换.ppt

    《数字电子技术基础》第五版的第十一章主要探讨了数模和模数转换的概念及其在实际应用中的重要性。数模转换器(D/A转换器)和模数转换器(A/D转换器)是数字电子技术中的关键组件,它们在处理模拟信号与数字信号之间...

    数字电路课件:第十一章 数模和模数转换(电子).ppt

    本章课件主要围绕两个关键器件展开讲解:数模转换器(D/A转换器)和模数转换器(A/D转换器)。 首先来看数模转换器(D/A转换器),它的主要作用是把计算机内部使用的数字信号转换为模拟信号,这对于连接数字系统与...

Global site tag (gtag.js) - Google Analytics