1

我正在尝试这样做:

  1. 我 FTP 一个包含单个单词的大文件(~144,000,每行一个单词)

  2. 我需要打开上传的文件并创建 100 行的文件,每行最多一个字(01.txt、02.txt 等)。

  3. 我希望在创建 100 的文件后从原始文件中删除已处理的 100。

服务器是共享的,但如果需要,我可以安装模块。

现在,我的代码非常粗糙,因为我的知识非常有限。一个问题是将整个文件打开到一个数组中?我假设共享服务器没有足够的内存来打开这么大的文件并一次全部读入内存?我只想要前 100 行。下面只是打开一个小到可以加载的文件并将 100 行放入一个数组中。没有其他的。我打字很快,所以可能有几个问题,但是显示我有限的知识和需要帮助。

 use vars qw($Word @Words $IN);
 my $PathToFile = '/home/username/public/wordlists/Big-File-Of-Words.txt';
 my $cnt= '0';
 open $IN, '<', "$PathToFile" or die $!;
 while (<$IN>) {
    chomp;
    $Word = $_; 
    $Word=~ s/\s//g;
    $Word = lc($Word);
    ######
    if ($cnt <= 99){
        push(@Words,$Word);
    }
    $cnt++;
}
close $IN;

非常感谢。

好的,我正在尝试实现以下代码:

    #!/usr/bin/perl -w
BEGIN {
my $b__dir = (-d '/home/username/perl'?'/home/username/perl':( getpwuid($>) )[7].'/perl');
unshift @INC,$b__dir.'5/lib/perl5',$b__dir.'5/lib/perl5/x86_64-linux',map { $b__dir . $_ } @INC;
}
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
print CGI::header();
my $WORD_LIST='/home/username/public/wordlists/Big-File-Of-Words.txt';
sed 's/ *//g' $WORD_LIST | tr '[A-Z]' '[a-z]' | split -l 100 -a6 - words.
print 'Done';
1;

但我得到:

syntax error at split-up-big-file.pl line 12, near "sed 's/ *//g'"
Can't find string terminator "'" anywhere before EOF at split-up-big-file.pl line 12.

最后: 好吧,我想出了一个有效的快速解决方案。不漂亮:

    #!/usr/bin/perl -w
BEGIN {
my $b__dir = (-d '/home/username/perl'?'/home/username/perl':( getpwuid($>) )[7].'/perl');
unshift @INC,$b__dir.'5/lib/perl5',$b__dir.'5/lib/perl5/x86_64-linux',map { $b__dir . $_ } @INC;
}
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use diagnostics;
print CGI::header();
my $sourcefile = '/home/username/public_html/test/bigfile.txt';
my $rowlimit   = 100;
my $cnt= '1';
open(IN, $sourcefile) or die "Failed to open $sourcefile";
my $outrecno = 1;
while(<IN>) {
  if($outrecno == 1) {
  my $filename= $cnt.'.txt';
    open OUT, ">$filename" or die "Failed to create $filename";
      $cnt++;
  }
  print OUT $_;
  if($outrecno++ == $rowlimit) {
    $outrecno = 1;
    close FH;
  }
}
close FH;

我在这里找到了足够的信息让我继续前进。谢谢...

4

3 回答 3

2

有一个您可能会觉得有趣的非 Perl 解决方案...

$ split -l 100 -a6 /home/username/public/wordlists/Big-File-Of-Words.txt words.

这会将您的大单词文件分成一堆文件,每个文件不超过 100 行。文件名以 开头words.,后缀范围从aaaaaazzzzzz。因此,您将拥有words.aaaaaawords.aaaaabwords.aaaaac等。然后您可以将所有这些文件重新组合回您的单词列表,如下所示:

$ cat words.* > reconstituted_word_list.txt

当然,您想消除空格,同时将单词全部小写:

$ WORD_LIST=/home/username/public/wordlists/Big-File-Of-Words.txt
$ sed 's/ *//g' $WORD_LIST | tr '[A-Z]' '[a-z]' | split -l 100 -a6 - words.

是转换命令,将tr所有大写变为小写。split拆分文件,并删除sed空格。

Unix 的一大优势是它的文件处理能力。将大文件拆分成更小的部分并重新组合它们是一项常见的任务。也许你有一个大文件,但是一堆软盘,每个软盘不能容纳超过 100K。也许您正试图使用​​ UUCP 将这些文件复制到另一台计算机上,并且文件传输大小有 10K 的限制。也许您正在通过电子邮件进行 FTP,而系统无法处理大于 5K 的文件。

无论如何,我提出它是因为它可能比编写 Perl 脚本更容易解决您的情况。我是 Perl 的大写手,很多时候 Perl 可以比 shell 脚本更好更快地处理任务。但是,在这种情况下,这在 shell 中很容易处理。

于 2013-05-07T15:06:14.187 回答
2

这是一个基于对您的代码进行轻微修改的解决方案,它应该可以按照您想要的方式工作。

它循环遍历输入文件的所有行,并且对于每 100 行,它将写入自上次写入(或开始)以来遇到的单词的单词列表。如果剩余的eof($IN)行少于 100,则检查是捕获它们。

use strict;
use warnings;

my $PathToFile = '/home/username/public/wordlists/Big-File-Of-Words.txt';

open my $IN, '<', "$PathToFile" or die $!;

my $cnt = 0;
my $cnt_file = 0;
my @Words;

while ( my $Word = <$IN> ) {
    chomp $Word; 
    $Word =~ s/\s//g;
    $Word = lc($Word);
    ######

    push(@Words,$Word);
    if ( !(++$cnt % 100) || eof($IN) ) {
       $cnt_file++;
       open my $out_100, '>', "file_$cnt_file.txt" or die $!;
       print  $out_100 join("\n", @Words), "\n";
       close $out_100;
       @Words = ();
    }
}
于 2013-05-07T19:12:10.593 回答
0

这是一个纯粹的 Perl 解决方案。问题是您想在每 100 行之后创建文件。

为了解决这个问题,我有两个循环。一个是无限循环,另一个循环 100 次。在进入内部循环之前,我创建了一个用于写作的文件,并且每行写一个单词。当内部循环结束时,我关闭文件,增加 my$output_file_num然后打开另一个文件进行输出。

一些变化:

  • 我使用use warnings;and use strict(当你指定你想要 Perl 版本 5.12.0 或更高版本时包括在内)。
  • 不要使用use vars;. 这是过时的。如果您必须使用包变量,请使用our而不是声明变量my。什么时候应该使用包变量?如果你不得不问这个问题,你可能不需要包变量。99.999% 的时间,简单地使用my来声明一个变量。
  • constant用来定义你的word文件。这样可以在需要时轻松移动文件。
  • Mys/../../不仅删除了开头和结尾的空格,而且还小写了我的单词。删除整^\s*(.*?)\s*$行,但在单词的开头和结尾捕获没有空格的单词。.*?类似于,.*不贪婪。它将匹配可能的最小值(在这种情况下不包括单词末尾的空格)。
  • 注意我定义了一个标签INPUT_WORD_LIST。我用它来强制我的内部最后退出外部循环。
  • 我利用了$output_word_list_fh仅在循环中定义的事实。一旦我离开循环,由于$output_word_list_fh超出范围,文件会自动为我关闭。

和程序:

#!/usr/bin/env perl

use 5.12.0;
use warnings;
use autodie;

use constant WORD_FILE => "/home/username/public/wordlists/Big-File-Of-Words.txt";

open my $input_word_list_fh, "<", WORD_FILE;

my $output_file_num = 0;

INPUT_WORD_LIST:
for (;;) {
    open my $output_word_list_fh, ">", sprintf "%05d.txt", $output_file_num;
    for my $line (1..100) {
        my $word;
        if ( not $word = <$input_word_list_fh> ) {
            last INPUT_WORD_LIST;
        }
        chomp $word;
        $word =~ s/^\s*(.*?)\s*$/\L$1\E/;
        say {$output_word_list_fh} "$word";
    }
    close $output_word_list_fh;
    $output_file_num += 1;
}
close $input_word_list_fh;
于 2013-05-07T17:29:44.340 回答