【问题标题】:How should I print out a particular character in the file after reading the file?读取文件后如何打印文件中的特定字符?
【发布时间】:2010-11-01 11:36:43
【问题描述】:

我正在使用 perl 脚本读取文件。该文件由具有不同字符的字符串组成,我应该识别包含字符“X”的字符串。我想知道我应该如何(1) 打印此字符串(包含'X')以及(2) 将此字符串写入另一个文件(3) 计算'X' 的数量整个文件中的字符。下面的脚本再次打印整个文件。有什么建议吗?

#!/use/bin/perl
use strict;
use warnings;

open (FILE, "/home/user/Desktop/infile.phy") || die "cant open file\n";
my @body = <FILE>;
close (FILE);
my $count= 0;
my $string = '';
foreach $_(@body){
    if ($_ =~ m/[X]/){
        print "$_";
        $count++;
        print $count;
    }
    else {
        print ;
    }
}
exit;

【问题讨论】:

  • 我也在想同样的事情,但它很容易成为介绍性文本中的一个示例问题。
  • 在某些时候,您需要打开“另一个文件”并确保写入它。另外,尽量避免使用这种形式的“开放”;使用一个返回文件句柄的形式,以便与常规 $variable 一起使用: open($fh, "filename");或其中一种变体。
  • 就本练习而言,没有明显的理由将整个文件放入数组中。阅读循环中的每一行会更明智: while ($line = ) { ...check line and print... }
  • @Sinur 不,这不是家庭作业。我是 perl 新手,这是我正在编码的大问题的一小部分。感谢您的回复!

标签: perl file-handling string-matching


【解决方案1】:

既然是代码审查,那我们就一个一个来吧:

#!/use/bin/perl

那个 shebang 行很可能是一个错字。应该是

#!/usr/bin/perl

或任何which perl 在您的系统上返回。

use strict;
use warnings;

很好。

open (FILE, "/home/user/Desktop/infile.phy") || die "cant open file\n";

当您可以使用词法文件句柄时,不需要包全局文件句柄。如今,open 的 3 参数形式更为可取。此外,错误消息应指示您无法打开的文件:

my $filename = '/home/user/Desktop/infile.phy';
open my $input, '<', $filename
    or die "Cannot open '$filename' for reading: $!";

my @body = <FILE>;

您正在将文件放入数组中。在这种情况下,这是完全没有必要的。

my $count  = 0;
my $string = '';

在尽可能小的范围内声明和初始化(如有必要)任何变量。

my $count;

变量$string 未在代码中的其他任何地方使用。

foreach $_(@body){

这很愚蠢。 for 使用 $_ 如果没有指定循环变量。如果您改为指定一个词法循环变量,则更容易保持直截了当。

for my $line ( @body ) {

但是,我认为您不应该对文件进行嗑药。

        if ($_ =~ m/[X]/){

如果该行包含 X,则匹配成功。因此,它等同于 /X/。但是,这不会告诉您包含“X”的单词。为此,您需要确定单词是什么并在单词级别进行匹配。

考虑到所有这些,请考虑以下脚本。我对我认为是一个词的东西做了一个简化的假设。您应该能够在此基础上满足所有要求:

#!/usr/bin/perl

use strict;
use warnings;

my $filename = "$ENV{TEMP}/test.txt";
open my $input, '<', $filename
    or die "Cannot open '$filename' for reading: $!";

my $count;

while ( my $line = <$input> ) {
    my @words = grep { /X/ } split /\b/, $line;
    $count += @words;
    print join(', ', @words), "\n";
}

print "$count\n";

__END__

更新:如果您不关心在每一行中查找具有一个或多个 X 字符的单词,则 while 循环将被简化:

while ( <$input> ) { 
    $count += (my @matches = /(X)/g );
    print if @matches;
}

通过使用 $_。然而,这可能是低效的(假设我们正在保存每个匹配的 X 字符)。在这种情况下,tr 效果最好:

my ($count, $n);
$n = tr/X// and $count += $n and print while <$input>;

【讨论】:

  • 我同意您的所有评论。但是,问题中的第 3 点要求“计算整个文件中 'X' 字符的数量”。相反,您的解决方案会计算包含“X”字符的单词(字符串?取决于“字符串”的定义)的数量。
  • @blixtor:感谢您的关注。当然,每个单词可以包含多个 X 字符。事实上,我现在意识到 OP 并不关心将行拆分成单词等。
  • 3-arg 形式的 open 有时有用有时无用。始终安全地使用 2-arg open 很容易,有时您希望它能够从 open pragma 或 -C 开关中获取默认 IO 层。如果你要批评 2-arg opens,至少要说“因为有一天你可能会不安全地使用变量文件名”,而不仅仅是“这是新的做法”。
  • 在没有 X 的文件上尝试简化的 while 循环版本,看看为什么 $count 应该初始化为 0 :)
  • @ysth Arrrrrrgh!这只是证明if 声明完全没有必要。
【解决方案2】:

假设您的问题中的“字符串”等于“行”:

use strict;
use warnings;

@ARGV=qw(/home/user/Desktop/infile.phy);

my $count = 0;
open my $outfile, '>', 'outfile' or die $!;
while (<>) {
  my $cnt = tr/X/X/;
  if ($cnt) {
    print;
    print $outfile $_;
  }
  $count += $cnt;
}

close $outfile or die $!;

print $count;

【讨论】:

    【解决方案3】:

    您正在 if 子句的两个分支中打印 $_。去掉 else 分支。

    【讨论】:

    • 对于新手来说,'print ;' 可能并不明显打印“$_”,但这就是发生的事情。
    • 完全正确。我本来可以更详细一点。对不起。
    猜你喜欢
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多