perl处理文本经验积累(不断更新中)

来源:互联网 发布:淘宝客户进店逗留时间 编辑:程序博客网 时间:2024/05/06 02:11

1. 把同根路径不同文件包中同名的文件合并

 例子:

 作用描述:  问题:
现有五个目录 分别存放5个领域的文件
F:/.../fold/canyin/sys
F:/.../fold/jiaotong/sys
F:/.../fold/lvyou/sys
F:/.../fold/shangwu/sys
F:/.../fold/tiyu/sys

而每个
F:/.../fold/xxx/sys目录
下面有
18个文件:
text(0).txt
text(1).txt
....
text(16).txt
text(17).txt

想把五个领域目录下的文件名相同的文件合并成一个文件

比如:
all_text(0).txt = 
(F:/.../fold/canyin/sys/text(0).txt) 
+ (F:/.../fold/jiaotong/sys/text(0).txt)
+ (F:/.../fold/lvyou/sys/text(0).txt) 
+ (F:/.../fold/shangwu/sys/text(0).txt)
+ (F:/.../fold/tiyu/sys/text(0).txt)
这里的'+' 表示文件合并的意思
即后面处于不同目录下面的五个同名文件将被合并到all_text(0).txt文件中

#!
@person=qw(canyin jiaotong lvyou shangwu tiyu);
for($i=0;$i<18;$i++) {
        $src=join('+',map{$_."//sys//test_part_result_by_index($i).txt"} @person);
        print $src ,"/n";
        system("copy $src fold1_all_text($i).txt");
}

2. 简易获取当前目录下所有文件名

 一般是用CWD模块,下面这个更简洁

#!
#####
#给目录下面的文件改名字
while($file=glob('*.txt')) {#glob 取得当前目录下的文件名
        print "$file/n";
        $newfile = "canyin_".$file;
        rename($file,$newfile);
        print "$newfile/n";
}

3. 去除文件每行前标号

在EBMT翻译时,为防止串行一般在每行前加标号,格式如:[0001234]

在评测前,需要去掉之,代码如下:  写成批处理即可运行。

#!                                        
$inputfile  =shift ;
$outputfile = shift;
open IN,"<$inputfile" or die "can not open file : $inputfile/n";
open OUT,">$outputfile" or die "can not open file : $outputfile/n";
foreach $str (<IN>){

$str =~s/^/[( /d+ )/]//g;#去掉行首[ 12121212 ]
$str =~s/^ //g;#去掉行首空格
print OUT $str;
}

4. 从评测结果文件中提取结果:

#!

$inputfile = shift;

$outputfile = shift;
open IN ,$inputfile or die "can not open file,$!/n ";
open OUT, ">$outputfile" or die"can not open >out.txt,$!/n";

my $contents = <IN>;
my @system_names;
$sys = "system name= /"";
$nist5 = "Nist5Score=/"";
$bleu5 = "Bleu5Score=/"";
my @nist5score;
my @nist3score;
my @nist1score;
my @bleu5score;
my @bleu3score;
my @bleu3score;
#@system_names = /$sys(.*?)/"/g;
$sys ="<system name=/"";

@system_names=($contents=~/$sys(.*?)/"/gs);
@nist5score = ($contents=~/$nist5(.*?)/"/gs);
@bleu5score = ($contents=~/$bleu5(.*?)/"/gs);
print OUT join("/n",@system_names);
print OUT "/nnist5/n";
print OUT join("/n",@nist5score);
print OUT "/nbleu5/n";
print OUT join("/n",@bleu5score);
5。把文件随机化

#!/usr/bin/perl
#功能: 把输入文件随机化(每行是一个单位)
#方法:每次产生一个在总行数之间的随机整数,用一个标记数组看有是否已经输出。

use strict;
my $n = 100;
my $seed = 1;
#Do not call srand() (i.e. without an argument) more than once in
#a script. The internal state of the random number generator
#should contain more entropy than can be provided by any seed, so
#calling srand() again actually *loses* randomness.

my $infile = shift;
my $outfile = shift;
open(IN,$infile) || die "无法打开input.txt/n";
open (OUT,">$outfile")|| die "无法打开output.txt/n";

my @all = <IN>;
my $sen_num = @all;#总句子数
my $cur_num = 0;#目前提取的句数
my @lab ;#标记数组
my $selected = 100;
my $non_selected = 0;

srand(); 

#先把标记数组初始化
my $i=0;
for($i=0;$i<@all;$i++)
{
 $lab[$i] = $non_selected;
}

my $num = 0;
while($cur_num < $sen_num)
{
  $num = int rand($sen_num);
 
  if($lab[$num] != $selected)
  {
   print OUT @all[$num];
   
   $lab[$num] = $selected;
   $cur_num ++;
   #$num ++;
  }
}

6. 上面的随机做法效率很低,建议用下面这个很棒的shuffle做法。

#!
use List::Util 'shuffle';
@all = <STDIN>;
$num = @all;
@list = (0..$num-1);
@shuffled = shuffle(@list);
foreach $i(@shuffled){
 print $all[$i];
 }



7. 文件成行读入
   把一个文件读入一个字符串
方法:
 my $contents;
{
  local $/;
  $contents = <IN>;
}

my $contents = do {local $/; <IN>}
例子: 文件中以空行为语块分割的标记,把语块内部顺序保留,而语块间逆序输出。
#!
open IN,"input.txt";
open OUT,">output.txt";
my $contents;
{
  local $/;
  $contents = <IN>;
}
my @all = split("/n/n",$contents);#不同文件格式也可能是my @all = split("/n/r/n",$contents);
for(my $i=@all-1;$i>=0;$i--)
{
  print OUT $all[$i],"/n/n";
}
close(IN);
close(OUT);

8. 如何用foreach每次读取多句?
  那就用<FH>读三次,
while (!eof(FH)){
$line1 = <FH>;
$line2 = <FH>;
$line3 = <FH>;
...
}


9 (非)贪婪(non-greedy)匹配

? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,
匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,
而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
例如,对于字符串 "oooo",’o+?’ 将匹配单个"o",而 ’o+’ 将匹配所有 ’o’。

如果你使用一个旧的Perl版本, 并且你不想贪婪匹配, 你必须使用否定的字符类。(真的, 你正在得到一种限制的贪婪匹配)

在Perl的现在版本中, 你能通过在数量词后使用一个问号,
强迫进行非贪婪的最小匹配。 
同样的用户名匹配将是/.*?:/。现在这个.*?将尽可能匹配少的字符, 而不是尽可能多的字符,
所以它停在第一个冒号而不是最后一个冒号。

例子:
问题是这样的:
比如给一句话,形式如下:
I(i)/xx came(come)/xx ,(,)/xx ((()/xx {({)/xx how it like(how it like)/yy
解释格式:
词组,然后是用小括号包围的词组还原形式,然后是斜杠'/',然后是词性..

要求: 把还原形式去掉
例如上句想得到:
I/xx came/xx ,/xx (/xx {/xx how it like/yy

难点: 1. 词组可能是左小括号'(' 即可能有词组:  ((()/xx
      2. 各种标点,括号() [] {}等
      3. 好几个词的词组,如: How it like(how it like)/xx

做法: 拆分成一段一段来做吧,要不然用regexp处理各段之间的混淆很麻烦:

my $str="I(i)/xx came(come)/xx ,(,)/xx ((()/xx )())/x {({)/xx how it like(how it like)/yy";
my $res='';
while($str=~m|(.*?//S+)|g) {# 非贪婪匹配,否则结果就是 I/yy
        my $token=$1;
        $token=~s|/(/(/(/)|/(|g;
        $token=~s|/)/(/)/)|/)|g;
        $token=~s|/(.*/)||g;
        $res.=$token;
}
print $res,"/n";

 

原创粉丝点击