有这样一种数据类型:

我想将它整理成这样:

直接给出一段代码:
#! C:\other_disk\D_disk_software\perl64 -w
use utf8;
binmode(STDOUT,":utf8");
my %hash;
sub uniq {
return keys %{{map {$_=>1} @_}};
}
open(INPUT,"<1.txt")or die, $!;
open(OUTPUT,">2.txt")or die, $!;
foreach (<INPUT>) {
if(/^(\S+)(\s.*?)[\n\r]*$/){
$hash{$1} .= $2;
}
}
close INPUT;
foreach (sort keys %hash) {
my @elements = uniq (split ('\t', $hash{$_}));
print OUTPUT "$_\t", join(' ', sort @elements), "\n";
}
这段代码包含了perl语言的很多知识点。
我们来一行一行的看(接下来将用数字表示代码的行数,一行一行的进行解释):
------------------------------------------------------------------
1. #! C:\other_disk\D_disk_software\perl64 -w
我写的这段代码,对于windows系统下毫无意义,只是觉得应该在第一行写点什么东西。但是假如你在linux系统中运用perl的话,需要分两种情况来说明:第一种,如果你采用perl text.pl这种方式运行perl的脚本文件text.pl的话,那第一行也不需要,直接开始写你的代码就可以。第二种,如果你采用./text.pl来执行这个脚本文件,那么第一行必不可少,一般大家都这么写: #!/usr/bin/perl (指明perl解释器的路径)。
------------------------------------------------------------------
2. use utf8;
这是载入utf8模块的函数use,一般书写perl脚本是需要把所有你需要用到的模块在脚本的开头载入。(模块包括包,包包括函数,函数又叫子程序,也就是说一个模块可能包含许多个包和许多个函数)。
------------------------------------------------------------------
3. binmode(STDOUT,":utf8");
ok,说曹操曹操就到,binmode就是utf8模块中的一个函数,这行代码的意思是perl的标准输出采用utf8编码表(编码和计算机的原理有很大关系,这说起来话长,简单点说就是,假如你和别人对暗号的时候,这个暗号必须是在同一个密码本上的暗号,假如你用的密码本和别人不同,你就会被乱枪射死,在计算机上就会出现perl语言输出的文本为乱码)。
注意:其对应的标准输入的文件格式也要utf8。
------------------------------------------------------------------
4. my %hash;
就是声明一个私有哈希列表,类似与C语言的声明变量,就是告诉计算机给我准备一个叫%hash的列表,我准备向里面存取东西了。说到哈希,这里不得不提@arrey(数组),$var(变量)。perl语言中都有专门的符号表示他们。
------------------------------------------------------------------
5. 6. 7.
sub uniq {
return keys %{{map {$_=>1} @_}};
}
这其实也是一个函数啦,又叫子程序,sub uniq{}
指建立一个名字叫unqi的函数,其核心内容是位于{}
中的代码块:return keys %{{map {$_=>1} @_}};
这里说到函数就需要说函数参数的问题,使用函数就是向函数内部传递参数的过程,函数就是为了实现改变几个参数就可以重复利用的功能。perl语言中@_
就是接受传入函数参数的默认数组 ,$_
也是perl语言的一个默认变量。
map {$_=>1} @_
中map为一个函数,它实现的功能是遍历数组@_
中的每一个元素,并执行{$_=>1}
中的内容,即生成一个数组(第一个元素,1,第二个元素,1,第三个元素,1,...)。
接下在的知识点就是数组、哈希以及列表的嵌套功能。当将%{{数组}}
形式出现时就将数组转化为哈希,即(第一个元素=>1,第二个元素=>1,第三个元素=>1,...)。最后一步return keys %{}
就是将哈希中的键列出并返回给函数。所以呀,这个函数会返回一个字符串。
------------------------------------------------------------------
8. 9.
open(INPUT,"<1.txt")or die, $!;
open(OUTPUT,">2.txt")or die, $!;
这两行代码实际上本质一样,第一行是将1.txt文件中的内容写入到句柄INPUT中,第二行是将句柄OUTPUT的内容写入到中2.txt文件中。
后面的or die, $!
是指,如果前面的操作无法运行,则退出不在运行该脚本,并返回错误原因($!
)。$!
是perl中默认代表所有错误的一个标志吧。
------------------------------------------------------------------
10. 11. 12. 13. 14. 15.
foreach (<INPUT>) {
if(/^(\S+)(\s.*?)[\n\r]*$/){ #以任意个非空白字符开头,以任意个换行符或者回车符结尾的字符串(并且中间可以包含新行外的一个或者多个任意字符)
$hash{$1} .= $2;
}
}
close INPUT;
foreach (<INPUT>)
就是遍历文件句柄IUPUT中的内容,一行一行的来,有多少行就循环多少次,每一行执行一次代码块中的内容。
if(/^(\S+)(\s.*?)[\n\r]*$/)
指假如...成立则执行代码块中的内容。
下面我们只需要深究这个/^(\S+)(\s.*?)[\n\r]*$/
是什么意思。//
表示匹配,即/匹配内容/
;^
以...字符开头,$
表示以...字符结尾,因此意思就是以空字符开头,以0个或者任意个换行符或者以0个或者任意个回车符结尾的字符串,并且中间包含(\S+)
任意个非空白字符和(\s.*?)
任意字符串。
$hash{$1} .= $2
也可以写成
$hash{$1} = $hash{$1}.$2
中$1
就默认表示(\S+)
中的内容,$2
表示(\s.*?)
中的内容。.
代表将两个字符串合并。
因此,整个foreach循环结束后,就生成一个哈希(%hash)表包括:('1'=>'\ta\tk','2'=>'\tb\tl','3'=>'\tc\tm',...)
最后,养成好习惯,关闭句柄INPUT,节约内存。
------------------------------------------------------------------
16. 17. 18. 19
foreach (sort keys %hash) {
my @elements = uniq (split ('\t', $hash{$_}));
print OUTPUT "$_\t", join(' ', sort @elements), "\n";
}
sort keys %hash
将%hash
的键列出,并排序,相当于键值组成了一个列表。接着还是用foreach遍历这个列表,一个元素一个循环。
split ('\t', $hash{$_})
是将$hash
中键对应的值分割成数组,比如第一行(a,k),再将这个数组作为参数传递到uniq函数中,因此,my @element
就是(a,k)
join(' ', sort @elements)
将数组元素以空格连接成一个字符串,即a k
。
最后print OUTPUT "$_\t", join(' ', sort @elements), "\n";
,以键+字符串+换行符为格式打印到OUTPUT句柄中,每个键执行一个循环,知道所有键都执行完毕为止。
最终,OUTPUT句柄写入到2.txt文件中。
-------------------------------------------------------------------
源代码来源:
http://cn.voidcc.com/question/p-otfupjcv-rz.html(略作修改)
网友评论