首页 电脑 电脑学堂 查看内容

perl 5 教程 连载(五)

2005-6-7 04:31 696 0

摘要: 第九章 关联数组/哈希表 一、数组变量的限制    在前面讲的数组变量中,可以通过下标访问其中的元素。例如,下列语句访问数组@array的第三个元素:&nbs...
关键词: nbsp 数组 一个 元素 变量 节点 输出 关联 下标 word

第九章 关联数组/哈希表 一、数组变量的限制    在前面讲的数组变量中,可以通过下标访问其中的元素。例如,下列语句访问数组@array的第三个元素:    $scalar = $array[2];    虽然数组很有用,但它们有一个显著缺陷,即很难记住哪个元素存贮的什么内容。假如我们来写一个程序计算某文件中首字母大写的单词出现的次数,用数组来实现就比较困难,程序代码如下: 1 : #!/usr/local/bin/perl2 :3 : while ($inputline = <STDIN>) {4 :   while ($inputline =~ /\b[A-Z]\S+/g) {5 :     $word = $&;6 :     $word =~ s/[;.,:-]$//; # remove punctuation7 :     for ($count = 1; $count <= @wordlist;8 :         $count++) {9 :       $found = 0;10:       if ($wordlist[$count-1] eq $word) {11:         $found = 1;12:         $wordcount[$count-1] += 1;13:         last;14:       }15:     }16:     if ($found == 0) {17:       $oldlength = @wordlist;18:       $wordlist[$oldlength] = $word;19:       $wordcount[$oldlength] = 1;20:     }21:   }22: }23: print ("Capitalized words and number of occurrences:\n");24: for ($count = 1; $count <= @wordlist; $count++) {25:   print ("$wordlist[$count-1]: $wordcount[$count-1]\n");26: }     运行结果如下: Here is a line of Input.This Input contains some Capitalized words.^DCapitalized words and number of occurrences:Here: 1Input: 2This: 1Capitalized: 1     这个程序每次从标准输入文件读一行文字,第四行起的循环匹配每行中首字母大写的单词,每找到一个循环一次,赋给简单变量$word。在第六行中去掉标点后,查看该单词是否曾出现过,7~15行中在@wordlist中挨个元素做此检查,如果某个元素与$word相等,@wordcount中相应的元素就增加一个数。如果没有出现过,即@wordlist中没有元素与$word相等,16~20行给@wordlist和@wordcount增加一个新元素。二、定义    正如你所看到的,使用数组元素产生了一些问题。首先,@wordlist中哪个元素对应着哪个单词并不明显;更糟的是,每读进一个新单词,程序必须检查整个列表才能知道该单词是否曾经出现过,当列表变得较大时,这是很耗费时间的。    这些问题产生的原因是数组元素通过数字下标访问,为了解决这类问题,Perl定义了另一种数组,可以用任意简单变量值来访问其元素,这种数组叫做关联数组,也叫哈希表。    为了区分关联数组变量与普通的数组变量,Perl使用%作为其首字符,而数组变量以@打头。与其它变量名一样,%后的第一个字符必须为字母,后续字符可以为字母、数字或下划线。三、访问关联数组的元素    关联数组的下标可以为任何简单/标量值,访问单个元素时以$符号打头,下标用大括号围起来。例如: $fruit{"bananas"}$number{3.14159}$integer{-7}     简单变量也可作为下标,如:    $fruit{$my_fruit}四、增加元素    创建一个关联数组元素最简单的方法是赋值,如语句$fruit{"bananas"} = 1; 把1赋给关联数组%fruit下标为bananas的元素,如果该元素不存在,则被创建,如果数组%fruit从未使用过,也被创建。    这一特性使得关联数组很容易用于计数。下面我们用关联数组改写上面的程序,注意实现同样的功能此程序简化了许多。 1 : #!/usr/local/bin/perl2 :3 : while ($inputline = ) {4 :   while ($inputline =~ /\b[A-Z]\S+/g) {5 :     $word = $&;6 :     $word =~ s/[;.,:-]$//; # remove punctuation7 :     $wordlist{$word} += 1;8 :   }9 : }10: print ("Capitalized words and number of occurrences:\n");11: foreach $capword (keys(%wordlist)) {12:   print ("$capword: $wordlist{$capword}\n");13: }     运行结果如下: Here is a line of Input.This Input contains some Capitalized words.^DCapitalized words and number of occurrences:This: 1Input: 2Here: 1Capitalized: 1     你可以看到,这次程序简单多了,读取输入并存贮各单词数目从20行减少到了7行。    本程序用关联数组%wordlist跟踪首字母大写的单词,下标就用单词本身,元素值为该单词出现的次数。第11行使用了内嵌函数keys()。这个函数返回关联数组的下标列表,foreach语句就用此列表循环。    注:关联数组总是随机存贮的,因此当你用keys()访问其所有元素时,不保证元素以任何顺序出现,特别值得一提的是,它们不会以被创建的顺序出现。    要想控制关联数组元素出现的次序,可以用sort()函数对keys()返回值进行排列,如: foreach $capword (sort keys(%wordlist)) {  print ("$capword: $wordlist{$capword}\n");} 五、创建关联数组    可以用单个赋值语句创建关联数组,如:    %fruit = ("apples",17,"bananas",9,"oranges","none");    此语句创建的关联数组含有下面三个元素: 下标为apples的元素,值为17 下标为bananas的元素,值为9 下标为oranges的元素,值为none     注:用列表给关联数组赋值时,Perl5允许使用"=>"或","来分隔下标与值,用"=>"可读性更好些,上面语句等效于:    %fruit = ("apples"=>17,"bananas"=>9,"oranges"=>"none");六、从数组变量复制到关联数组    与列表一样,也可以通过数组变量创建关联数组,当然,其元素数目应该为偶数,如:    @fruit = ("apples",17,"bananas",9,"oranges","none");    %fruit = @fruit;    反之,可以把关联数组赋给数组变量,如:    %fruit = ("grapes",11,"lemons",27);    @fruit = %fruit;    注意,此语句中元素次序未定义,那么数组变量@fruit可能为("grapes",11,"lemons",27)或("lemons",27,"grapes",11)。    关联数组变量之间可以直接赋值,如:%fruit2 = %fruit1; 还可以把数组变量同时赋给一些简单变量和一个关联数组变量,如:    ($var1, $var2, %myarray) = @list;    此语句把@list的第一个元素赋给$var1,第二个赋给$var2,其余的赋给%myarray。    最后,关联数组可以通过返回值为列表的内嵌函数或用户定义的子程序来创建,下例中把split()函数的返回值--一个列表--赋给一个关联数组变量。 1: #!/usr/local/bin/perl2:3: $inputline = <STDIN>;4: $inputline =~ s/^\s+|\s+\n$//g;5: %fruit = split(/\s+/, $inputline);6: print ("Number of bananas: $fruit{\"bananas\"}\n");     运行结果如下: oranges 5 apples 7 bananas 11 cherries 6Number of bananas: 11 七、元素的增删    增加元素已经讲过,可以通过给一个未出现过的元素赋值来向关联数组中增加新元素,如$fruit{"lime"} = 1;创建下标为lime、值为1的新元素。    删除元素的方法是用内嵌函数delete,如欲删除上述元素,则:    delete ($fruit{"lime"});注意: 1、一定要使用delete函数来删除关联数组的元素,这是唯一的方法。2、一定不要对关联数组使用内嵌函数push、pop、shift及splice,因为其元素位置是随机的。 八、列出数组的索引和值    上面已经提到,keys()函数返回关联数组下标的列表,如: %fruit = ("apples", 9, "bananas", 23, "cherries", 11); @fruitsubs = keys(%fruits);     这里,@fruitsubs被赋给apples、bananas、cherries构成的列表,再次提请注意,此列表没有次序,若想按字母顺序排列,可使用sort()函数。    @fruitindexes = sort keys(%fruits);    这样结果为("apples","bananas","cherries")。类似的,内嵌函数values()返回关联数组值的列表,如: %fruit = ("apples", 9, "bananas", 23, "cherries", 11); @fruitvalues = values(%fruits);     这里,@fruitvalues可能的结果为(9,23.11),次序可能不同。九、用关联数组循环    前面已经出现过利用keys()函数的foreach循环语句,这种循环效率比较低,因为每返回一个下标,还得再去寻找其值,如: foreach $holder (keys(%records)){  $record = $records{$holder};}     Perl提供一种更有效的循环方式,使用内嵌函数each(),如: %records = ("Maris", 61, "Aaron", 755, "Young", 511);while (($holder, $record) = each(%records)) {  # stuff goes here}     each()函数每次返回一个双元素的列表,其第一个元素为下标,第二个元素为相应的值,最后返回一个空列表。    注意:千万不要在each()循环中添加或删除元素,否则会产生不可预料的后果。十、用关联数组创建数据结构    用关联数组可以模拟在其它高级语言中常见的多种数据结构,本节讲述如何用之实现:链表、结构和树。1、(单)链表    链表是一种比较简单的数据结构,可以按一定的次序存贮值。每个元素含有两个域,一个是值,一个是引用(或称指针),指向链表中下一个元素。一个特殊的头指针指向链表的第一个元素。    在Perl中,链表很容易用关联数组实现,因为一个元素的值可以作为下一个元素的索引。下例为按字母顺序排列的单词链表: %words = ("abel", "baker", "baker", "charlie", "charlie", "delta", "delta", ""); $header = "abel";     上例中,简单变量$header含有链表中第一个单词,它同时也是关联数组第一个元素的下标,其值baker又是下一个元素的下标,依此类推。    下标为delta的最后一个元素的值为空串,表示链表的结束。    在将要处理的数据个数未知或其随程序运行而增长的情况下,链表十分有用。下例用链表按字母次序输出一个文件中的单词。 1 : #!/usr/local/bin/perl2 :3 : # initialize list to empty4 : $header = "";5 : while ($line = <STDIN>) {6 :   # remove leading and trailing spaces7 :   $line =~ s/^\s+|\s+$//g;8 :   @words = split(/\s+/, $line);9 :   foreach $word (@words) {10:     # remove closing punctuation, if any11:     $word =~ s/[.,;:-]$//;12:     # convert all words to lower case13:     $word =~ tr/A-Z/a-z/;14:     &add_word_to_list($word);15:   }16: }17: &print_list;18:19: sub add_word_to_list {20:   local($word) = @_;21:   local($pointer);22:23:   # if list is empty, add first item24:   if ($header eq "") {25:     $header = $word;26:     $wordlist{$word} = "";27:     return;28:   }29:   # if word identical to first element in list,30:   # do nothing31:   return if ($header eq $word);32:   # see whether word should be the new33:   # first word in the list34:   if ($header gt $word) {35:     $wordlist{$word} = $header;36:     $header = $word;37:     return;38:   }39:   # find place where word belongs40:   $pointer = $header;41:   while ($wordlist{$pointer} ne "" &&42:     $wordlist{$pointer} lt $word) {43:     $pointer = $wordlist{$pointer};44:   }45:   # if word already seen, do nothing46:   return if ($word eq $wordlist{$pointer});47:   $wordlist{$word} = $wordlist{$pointer};48:   $wordlist{$pointer} = $word;49: }50:51: sub print_list {52:   local ($pointer);53:   print ("Words in this file:\n");54:   $pointer = $header;55:   while ($pointer ne "") {56:     print ("$pointer\n");57:     $pointer = $wordlist{$pointer};58:   }59: }     运行结果如下: Here are some words.Here are more words.Here are still more words.^DWords in this file:areheremoresomestillwords     此程序分为三个部分: 主程序:读取输入并转换到相应的格式。 子程序:add_word_to_list,建立排序单词链表。 子程序:print_list,输出单词链表     第3~17行为主程序,第4行初始化链表,将表头变量$header设为空串,第5行起的循环每次读取一行输入,第7行去掉头、尾的空格,第8行将句子分割成单词。9~15行的内循环每次处理一个单词,如果该单词的最后一个字符是标点符号,就去掉。第13行把单词转换成全小写形式,第14行传递给子程序add_word_to_list。    子程序add_word_to_list先在第24行处检查链表是否为空。如果是,第25行将单词赋给$header,26行创建链表第一个元素,存贮在关联数组%wordlist中。如果链表非空,37行检查第一个元素是否与该单词相同,如果相同,就立刻返回。下一步检查这一新单词是否应该为链表第一个元素,即其按字母顺序先于$header。如果是这样,则:    1、创建一个新元素,下标为该新单词,其值为原第一个单词。    2、该新单词赋给$header。    如果该新单词不该为第一个元素,则40~44行利用局域变量$pointer寻找其合适的有效位置,41~44行循环到$wordlist{$pointer}大于或等于$word为止。接下来46行查看该单词是否已在链表中,如果在就返回,否则47~48行将其添加到链表中。首先47行创建新元素$wordlist{$word},其值为$wordlist{$pointer},这时$wordlist{$word}和$wordlist{$pointer}指向同一个单词。然后,48行将$wordlist{$pointer}的值赋为$word,即将$wordlist{$pointer}指向刚创建的新元素$wordlist{$word}。    最后当处理完毕后,子程序print_list()依次输出链表,局域变量$pointer含有正在输出的值,$wordlist{$pointer}为下一个要输出的值。    注:一般不需要用链表来做这些工作,用sort()和keys()在关联数组中循环就足够了,如: foreach $word (sort keys(%wordlist)) {  # print the sorted list, or whatever }     但是,这里涉及的指针的概念在其它数据结构中很有意义。2、结构    许多编程语言可以定义结构(structure),即一组数据的集合。结构中的每个元素有其自己的名字,并通过该名字来访问。    Perl不直接提供结构这种数据结构,但可以用关联数组来模拟。例如模拟C语言中如下的结构: struce{  int field1;  int field2;  int field3; }mystructvar;     我们要做的是定义一个含有三个元素的关联数组,下标分别为field1、field2、field3,如: %mystructvar = ("field1" , "" ,      "field2" , "" ,      "field3" , "" ,);     像上面C语言的定义一样,这个关联数组%mystrctvar有三个元素,下标分别为field1、field2、field3,各元素初始值均为空串。对各元素的访问和赋值通过指定下标来进行,如:    $mystructvar{"field1"} = 17;3、树    另一个经常使用的数据结构是树。树与链表类似,但每个节点指向的元素多于一个。最简单的树是二叉树,每个节点指向另外两个元素,称为左子节点和右子节点(或称孩子),每个子节点又指向两个孙子节点,依此类推。    注:此处所说的树像上述链表一样是单向的,每个节点指向其子节点,但子节点并不指向父节点。    树的概念可以如下描述: 因为每个子节点均为一个树,所以左/右子节点也称为左/右子树。(有时称左/右分支) 第一个节点(不是任何节点的子节点的节点)称为树的根。 没有孩子(子节点)的节点称为叶节点。     有多种使用关联数组实现树结构的方法,最好的一种应该是:给子节点分别加上left和right以访问之。例如,alphaleft和alpharight指向alpha的左右子节点。下面是用此方法创建二叉树并遍历的例程: 1 : #!/usr/local/bin/perl2 :3 : $rootname = "parent";4 : %tree = ("parentleft", "child1",5 :          "parentright", "child2",6 :          "child1left", "grandchild1",7 :          "child1right", "grandchild2",8 :          "child2left", "grandchild3",9 :          "child2right", "grandchild4");10: # traverse tree, printing its elements11: &print_tree($rootname);12:13: sub print_tree {14:   local ($nodename) = @_;15:   local ($leftchildname, $rightchildname);16:17:   $leftchildname = $nodename . "left";18:   $rightchildname = $nodename . "right";19:   if ($tree{$leftchildname} ne "") {20:     &print_tree($tree{$leftchildname});21:   }22:   print ("$nodename\n");23:   if ($tree{$rightchildname} ne "") {24:     &print_tree($tree{$rightchildname});25:   }26: }     结果输出如下: grandchild1child1grandchild2parentgrandchild3child2grandchild4     该程序创建的二叉树如下图:     注意函数print_tree()以次序“左子树、节点、右子树”来输出各节点的名字,这种遍历次序称为“左序遍历”。如果把第22行移到19行前,先输出节点明,再输出左子树、右子树,则为“中序遍历”,如果把第22行移到25行后,输出次序为左子树、右子树、节点,则为“右序遍历”。    可以用同样的方法,即连接字符串构成下标,来创建其它的数据结构,如数据库等。 第十章 格式化输出     我们已经见过用print函数将原始的未格式化的文本输出到文件,本章讲述如何用函数write和打印格式来生成格式化的输出。一、定义打印格式     定义打印格式的关键字为format,语法为: format formatname = lines_of_output .     打印格式名formatname的命名规则与一般变量相同。结束行为一个句号,此行不能有任何其它字符,包括空格,句号必须是该行第一个字符。     打印格式的定义象子程序一样可以放在任何地方,甚至可以放在条件语句中,但是最好把它们集中放在程序的开头或结尾。 二、显示打印格式    打印格式的显示有两步:     1、将系统变量$~设成所要使用的格式     2、调用函数write    例如: 1 : #!/usr/local/bin/perl2 : 3 : $~ = "MYFORMAT";4 : write;5 : 6 : format MYFORMAT =7 : ===================================8 : Here is the text I want to display.9 : ===================================10: .     结果输出如下: $ program===================================Here is the text I want to display.===================================$     如果不用$~指定打印格式,Perl解释器就假定要使用的格式名与要写入的文件变量同名,在本例中,如果不指定使用MYFORMAT,则Perl解释器试图使用名为STDOUT的打印格式。三、在打印格式中显示值    我们使用打印格式的主要原因当然是格式化存贮在简单变量或数组变量中的值从而生成可读性好的输出,这一目的用“值域”来实现。每个值域指定一个值,如变量或表达式,调用write函数时,该值就以值域指定的格式显示。1、通用的打印格式    打印格式的一个缺点是定义中包含了变量名,例如: format MYFORMAT ===========================================================The winning number is @<<<<<<!$winnum==========================================================.     当调用write输出此格式时,必须记着它使用了变量$winnum。用子程序和局域变量就可以创建更通用的打印格式。下例从STDIN输入一个文件并输出五个出现频率最高的字母及出现次数。 1 : #!/usr/local/bin/perl2 : 3 : while ($line = ) {4 :   $line =~ tr/A-Z/a-z/;5 :   $line =~ s/[^a-z]//g;6 :   @letters = split(//, $line);7 :   foreach $letter (@letters) {8 :     $lettercount{$letter} += 1;9 :   }10: }11: 12: $~ = "WRITEHEADER";13: write;14: $count = 0;15: foreach $letter (reverse sort occurrences16:       (keys(%lettercount))) {17:   &write_letter($letter, $lettercount{$letter});18:   last if (++$count == 5);19: }20: 21: sub occurrences {22:   $lettercount{$a} <=> $lettercount{$b};23: }24: sub write_letter {25:   local($letter, $value) = @_;26: 27:   $~ = "WRITELETTER";28:   write;29: }30: format WRITEHEADER =31: The five most frequently occurring letters are:32: .33: format WRITELETTER =34:   @: @<<<<<<35:   $letter, $value36: .     运行结果如下: $ program This is a test file. This test file contains some input. The quick brown fox jumped over the lazy dog. ^D The five most frequently occurring letters are: t: 10 e: 9 i: 8 s: 7 o: 6 $ 2、格式和局域变量    在上例中,你可能已经注意到子程序write_letter调用write输出字母及其出现次数,即使格式定义在子程序外部仍能正常工作。在第17行中将字母及其出现次数传递给该子程序,在子程序中,打印格式使用局域变量$letter和$value,这样保证了在foreach循环中每次输出当前的字母和值。    然而要注意的是,使用my定义的局域变量要求格式定义在子程序内部,否则就不会输出,因此,用write输出的局域变量一定要用local定义。(local和my详见《子程序》一章)    注:Perl4中没有my函数,故不会有此问题。3、选择值域格式    我们已经知道了打印格式和write函数怎么工作,现在来看看值域的格式,见下表: 格式 值域含义 @<<< 左对齐输出 @>>> 右对齐输出 @||| 中对齐输出 @##.##   固定精度数字   @* 多行文本     每个值域的第一个字符是行填充符,当使用@字符时,不做文本格式化。对文本的格式化稍后来讲。    在上表中,除了多行值域@*,域宽都等于其指定的包含字符@在内的字符个数,例如:     @###.##    表示七个字符宽,小数点前四个,小数点后两个。4、输出值域字符    在打印格式里,特定字符如@、<和>被看作值域定义,那么如何将它们输出呢?方法如下: format SPECIAL =This line contains the special character @."@". 四、输出到其它文件    缺省地,函数write将结果输出到标准输出文件STDOUT,我们也可以使它将结果输出到任意其它的文件中。最简单的方法就是把文件变量作为参数传递给write,如:     write (MYFILE);    这样,write就用缺省的名为MYFILE的打印格式输出到文件MYFILE中,但是这样就不能用$~变量来改变所使用的打印格式。系统变量$~只对缺省文件变量起作用,我们可以改变缺省文件变量,改变$~,再调用write,例如:     select (MYFILE);     $~ = "MYFORMAT";     write;    当select改变缺省文件变量时,它返回当前缺省文件变量的内部表示,这样我们就可以创建子程序,按自己的想法输出,又不影响程序的其它部分,如下: sub write_to_stdout {  local ($savefile, $saveformat);  $savefile = select(STDOUT);  $saveformat = $~;  $~ = "MYFORMAT";  write;  $~ = $saveformat;  select($savefile);} 五、分页    在输出到打印机时,可以在每页顶部输出相应的信息,这样的特殊文本叫页眉。定义页眉实际上就是定义名为filename_TOP的打印格式,例如给标准输出文件定义页眉如下:     format STDOUT_TOP =     Consolidated Widgets Inc. 1994 Annual Report     .    在页眉的定义中也可以包含值域,页眉中经常使用的一个特殊值是当前页码,存贮在系统变量$%中,如:     format STDOUT_TOP =     Page @<<.     $%     .    我们也可以通过改变系统变量$^改变定义页眉的打印格式名,与$~一样,$^只对当前缺省文件起作用,因此可以与select函数结合使用。    缺省情况下,每页长度为60行,可以通过改变$=来改变页长,如:     $= = 66; #页长设为66行    此赋值语句必须出现在第一个write语句前。    注:一般使用分页机制时不用print函数,因为当用write输出时,Perl解释器跟踪每页的当前行号。如果必须使用print而又不打乱页计数,可以调整系统变量$-。$-的含义是当前行到页末之间的行数,当$-达到零时,就开始新的一页,调整方法如:     print ("Here is a line of output\n");     $- -= 1;六、格式化长字符串    我们已经学过值域@*可以输出多行文本,但它完全将字符串原样输出,不加以格式化。在Perl中对长字符串(包含换行)进行格式化的值域定义很简单,只需把打头的@字符换成^就行了,这种文本格式化中,Perl解释器在一行中放置尽可能多的单词。每当输出一行文本,被输出的子串就从变量中删除,再次在域值中使用该变量就把剩下的字符串继续按格式输出。当内容已输出完毕,该变量就成了空串,再输出就会输出空行,为避免输出空行,可以在值域格式行首加一个~字符。见下例: 1 : #!/usr/local/bin/perl2 : 3 : @quotation = <STDIN>;4 : $quotation = join("", @quotation);5 : $~ = "QUOTATION";6 : write;7 : 8 : format QUOTATION =9 : Quotation for the day:10: -----------------------------11: ~  ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<12: $quotation13: ~  ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<14: $quotation15: ~  ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<16: $quotation17: -----------------------------18: .     运行结果如下: $ programAny sufficiently advanced programminglanguage is indistinguishable from magic.^DQuotation for the day:-----------------------------   Any sufficiently advanced programming language is    indistinguishable from magic. -----------------------------$     如果把打印格式中行首的~字符去掉,上面的输出结果中就会多一行空行。很明显,当字符串长度不明确时,这种用法很不方便,原因就在于它指明了输出的行数上限,超过这一上限的字符就不会被输出,解决方法很简单,就是在域值格式行首加两个~字符,这样就会持续按格式输出文本直到输出完毕,用此方法把上述程序改写如下: 1 : #!/usr/local/bin/perl2 : 3 : @quotation = <STDIN>;4 : $quotation = join("", @quotation);5 : $~ = "QUOTATION";6 : write;7 : 8 : format QUOTATION =9 : Quotation for the day:10: -----------------------------11: ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<12: $quotation13: -----------------------------14: .     这样运行结果相同。七、用printf格式化输出    还有一种容易掌握和使用的格式化输出函数,那就是printf,它与C语言中的printf基本上是相同的。printf有两个参数,一个是字符串,其中含有一个或多个域值形式,另一个是与各域值相对应的变量值按一定格式替换,如:     printf("The number I want to print is %d.\n", $number);    各种域值形式如下表: 域值   含义 %c 单个字符 %d 十进制整数 %e 科学计数法形式的浮点数   %f 普通形式(定点)浮点数 %g 紧缩形式浮点数 %o 八进制整数 %s 字符串 %u 无符号整数 %x 十六进制整数     一些使用细节如下: 1、在格式d、o、u或x中,如果整数值较大或可能较大,可加个l字符,意为长整型,如%ld。2、%字符后加正整数表示该域的最小宽度,如果输出结果宽度不足,则向右对齐,前面用空格补足,如果该正整数以数字0打头,则补足字符为0。若%字符后为负整数,则结果向右对齐。3、浮点数域值(%c、%f和%g)中可以指定小数点前后的宽度,如%8.3f意为总宽度为8个字符,小数点后(即小数部分)为3个字符,多出的小数部分四舍五入。4、在整数、字符或字符串的值域中使用如上的小数形式n.m,整数部分n为总宽度,小数部分m为输出结果的最大宽度,这样就保证了输出结果前至少有n-m个空格。 (未完)
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部