如何编写一个程序来读取文本文件并替换某些单词然后以不同的名称输出文本文件

时间:2017-05-12 05:29:37

标签: perl

在过去的3个小时里,我一直在努力解决这个问题,而且似乎无处可去。我在线搜索并观看了YouTube视频。

问题是: 编写一个Perl程序,读取下面附带的input.txt文件并编写一个名为output.txt的新文件。新文件应该用'old'替换字符串'new'的所有出现(无论大小写)。

这是我到目前为止所得到的,但似乎无处可去。

use strict;
use warnings; 

my $filename = 'WK5input.txt';
open(my $fh,  $filename)
  or die "Could not open file '$filename' $!";

while (my $row = <$fh>) {
  chomp $row;
  print "$row\n";
}

$_ =~ s/new/old/g;
open( $fh, '>', 'output.txt');

print $filename ;
close $filename;

4 个答案:

答案 0 :(得分:3)

最简单的方法是使用&#34;输入/输出方向&#34;。此功能适用于所有流行的操作系统。这意味着我们编写代码以从STDIN读取并写入STDOUT并依赖操作系统将这些代码连接到特定文件。

使用这种技术,您的代码可以简化为:

#!/usr/bin/perl

use strict;
use warnings;

while (<>) {
  s/new/old/gi;
  print;
}

并且(假设我们将其存储在名为new2old的文件中),我们将其称之为:

$ ./new2old < WK5input.txt > output.txt

通过这种方式,我们可以避免使用文件句柄完成所有这些繁琐的工作,最终得到一个更灵活的程序。例如,我们可以将另一个进程的输出传递到我们的程序中,如下所示:

$ ls | ./new2old

程序中的硬编码文件名通常不是最佳方法。

答案 1 :(得分:2)

首先,谢谢你提到这是作业。我建议告诉你的导师,你得到了完成作业的帮助。以下是一些建议以及一些增强功能:

#!/usr/bin/env perl

use strict;
use warnings;

# Don't hardcode variable names, read them from
# the command line. But, make sure you tell the
# user what went wrong if they are not specified.

if (@ARGV != 2) {
    die "Need input and output filenames\n";
}

# Assign the filenames

my ($infile, $outfile) = @ARGV;

# Error messages due to open failure must indicate
# the name of the file on which the operaton was
# attempted and the nature of the operation.
# By enclosing filenames in nonspace characters,
# you make it obvious if there are some unexpected
# characters in the name of the file.

open my $in, '<', $infile
    or die "Cannot open '$infile' for reading: $!";

open my $out, '>', $outfile
    or die "Cannot open '$outfile' for writing: $!";

while (my $line = <$in>) {
    # No need to chomp (remove the EOL) if you are just
    # going to print lines to another file
    $line =~ s/old/new/;

    # There is no comma between the output filehandle and
    # the string to be printed. If you put a comma, you will
    # get the stringification of $out and $line both printed
    # on STDOUT.
    print $out $line;
}

# While lexical filehandles are automatically closed
# when they go out of scope, it is good to explicitly
# close them, especially handles opened for writing.
#
# We did not check if each print succeeded. This is
# your last chance to find out if everything worked.

close $out
    or die "Failed to close output handle to '$outfile': $!";

close $in
    or die "Failed to close input handle to '$infile': $!";

答案 2 :(得分:0)

使用各种快捷方式(可能禁止您的作业),您可以这样做:
perl -pe "s/new/old/gi" WK5input.txt > output.txt

但是,对于你的家庭作业的特殊情况,你已经合理地接近了目标,但很多细节必须修复。
(请注意,我错过了其中一个细节,不区分大小写。如果您提供了适当的样本输入和所需的输出,那就不会发生。您可能想要阅读[mcve]。)
我列出了一些假设,其中特殊的侧面要求将您的任务与通常的目标区分开来,以便做出有效的解决方案。

我故意在这里提供一个尽可能接近您自己版本的解决方案,因为我相信看到一些让您的版本工作的小改动对您来说比上面的优化版本更有帮助。那一个是如此紧凑,它完整隐藏你有多接近。
检查中间版本的其他答案,既没有完全优化也没有面向作业。 对于优化的解决方案,有些人甚至会跳过perl并使用awk,或者为了历史性的大脑锻炼,使用sed。

这些是对隐含规则的一些假设,
我猜你应该遵守:

  • 编写一个涵盖所有要求的perl程序,
    即没有使用shell功能,没有其他工具
  • 不要使用命令行参数
    (只是因为你没有尝试过;也许你还没有在课程中覆盖它们)
  • 逐行使用处理
    (只是因为你在尝试中这样做了;也许你还没有涵盖课程中的其他方法)
  • 不要使用&#34;模糊perl魔法&#34;,例如命令行选项-pe`,
    虽然它们非常方便 (特殊情况/解释&#34;没有shell&#34;规则)

如果这些猜测规则中的任何规则不适用于您的作业,请查看其他答案。它们提供了有趣的替代方案。

# nice touch, using these is very good practice
use strict;
use warnings; 

# Not necessary, but good practice: collect the "my"s in one place soon.
# This supports self-documenting inside the code.
# Doing it with the "my" at the first use is an aleternative option and preferred by some.
my $filename = 'WK5input.txt';  # file name   for the input file
my $fhin;                        # file handle for the input file
my $fhout;                       # file handle for the output file
my $row;                         # variable with currently processed line

# Prefer to use the three parameter version of "open", explicitly stating the mode.
open($fhin, '<', $filename) # two file handles are needed, use different names
  or die 'Could not open input  file "'.$filename.'" '.$!;
# I chose to concatenate both variables (file name and failure reason) explicitly,
# to some text inside '...', which can be more efficiently handled by perl interpreter.
# This saves work on text inside "..." and is more self explaining, i.e. it is easier
# to understand at the first reading what the code does.

# The second file handle is setup here, to read from input and write to output at the same time.
open($fhout, '>', 'output.txt')
  or die 'Could not open output file output.txt '.$!;

while ($row = <$fhin>) { # you are reading into a dedicated variable here ...

  # There was the code "chomp $row;" here. 
  # This removes the newline from ther end of the line, if there is one.
  # It is not needed if you are going to append the newline again before printing.

  $row =~ s/new/old/gi;   # ... you need to use the variable here, instead of "$_"
  # The additional "i" behind the "g", makes the search for "new", "New", "NEW" case insensitive.
  # Credits to other answer and comments for finding the requirement I missed.

  # I accept the requirement to replace new->old, though it seems strange.
  # I itched to replace old->new.

  print $fhout $row; # print into the output file instead of to stdout
  # You had an additional "\n" at the end, which was in fact needed, but only
  # because of the "chomp" a few lines above.
  # Also, you had the variable in quotes, i.e. "$row\n". That uses some time for interpreting
  # the text inside the quotes. If you only want to print the content of a variable, then
  # only print the variable outside of quotes.
}

# There was the code "$_ =~ s/new/old/g;" here, it was moved into the loop.
# Compare to a different answer to see a solution which used a single global replace on
# a variable with all the input. Instead, I decided to go for line by line processing in
# a loop, because it seemed closer to your approach.

# There was the code "open( $fh, '>', 'output.txt');" here it was moved to before the loop.
# There was the code "print $filename ;" here. It was deleted, because it seems not to be
# required by the assignment. Printing the modified content is done line by line inside the
# loop. 

# Closing file handles instead of file name:
close $fhin;  
close $fhout;

(StackOverflow建议不要立即提供完整的家庭作业问题解决方案 我将其解释为&#34; ...对于尚未接近解决方案的作业问题&#34; 我提供了一个解决方案,因为我认为你的尝试非常接近 足够接近,可以向您展示最后的细节,比较一些有效的东西。把它作为一种恭维 StackOverflow还建议以有用的方式让学生沿着他们已经看到的方式进一步学习。只提供优化的,精细调整的最终版本,作为这个答案的一个开头,对他们来说并不具有建设性 这当然不是我答案中任何非常糟糕的代码的借口,所以每个人都可以随意指出它。然而,当编辑时,请坚持我的目标,保持接近OP的尝试。)

答案 3 :(得分:-2)

试试这个:

use strict;
use warnings; 

my $filename = 'WK5input.txt';

open(my $tmp, "<", $filename) or die "Couldn't able to open a file...: $!\n";
my $storeline = "";
while(my $line = <$tmp>)
{
    $line=~s/new/old/g;
    $storeline .= $line;
}

open(my $out, ">", "Output.txt") or die "Couldn't able to open a file...: $!\n";
print $out $storeline;
close($out);
close($tmp);

在处理I / O时,有一个 多种方式 来完成任务。这仅基于您的问题/理解目的。

一旦你关闭了while循环,你也无法获得临时变量[特殊变量]。

 $_ =~ s/new/old/g;
 open( $fh, '>', 'output.txt');