【问题标题】:Perl: Substitute text string with value from list (text file or scalar context)Perl:用列表中的值替换文本字符串(文本文件或标量上下文)
【发布时间】:2013-03-25 10:07:14
【问题描述】:

我是 perl 新手,但读过 Schwartz、foy 和 Phoenix 的“Learning Perl”,对语言的理解很薄弱。即使在使用了这本书和网络之后,我仍然在苦苦挣扎。

我的目标是能够做到以下几点:

  1. 搜索特定文件夹(当前文件夹)并获取带有完整路径的文件名。使用完整路径和当前文件夹名保存文件名。

  2. 打开一个模板文件并在特定位置(例如使用替换)以及当前文件夹名(在同一文本文件的另一个位置,我还没有做到这一点)插入具有完整路径的文件名。

  3. 将新修改的文​​件保存到特定位置(当前文件夹)的新文件中。

我有许多要处理的文件/文件夹,并计划将 perl 程序复制到每个文件夹中,以便 perl 程序可以创建新的。

到目前为止,我已经...:

use strict;
use warnings;
use Cwd;
use File::Spec;
use File::Basename;
my $current_dir = getcwd;
open SECONTROL_TEMPLATE, '<secontrol_template.txt' or die "Can't open SECONTROL_TEMPLATE: $!\n";
my @secontrol_template = <SECONTROL_TEMPLATE>;
close SECONTROL_TEMPLATE;
opendir(DIR, $current_dir) or die $!;
my @seq_files = grep {
    /gz/
    } readdir (DIR);
open FASTQFILENAMES, '> fastqfilenames.txt' or die "Can't open fastqfilenames.txt: $!\n";
my @fastqfiles;
foreach (@seq_files) {
    $_ = File::Spec->catfile($current_dir, $_);
    push(@fastqfiles,$_);
}
print FASTQFILENAMES @fastqfiles;
open (my ($fastqfilenames),  "<", "fastqfilenames.txt") or die "Can't open fastqfilenames.txt: $!\n";
my @secontrol;
foreach (@secontrol_template) {
    $_ =~ s/@/$fastqfilenames/eg;
    push(@secontrol,$_);
}
open SECONTROL, '> secontrol.txt' or die "Can't open SECONTROL: $!\n";
print SECONTROL @secontrol;
close SECONTROL;
close FASTQFILENAMES;

我的问题是我无法弄清楚如何使用我的文件列表来替换模板文本文件中的“@”:

my @secontrol;
foreach (@secontrol_template) {
    $_ =~ s/@/$fastqfilenames/eg;
    push(@secontrol,$_);
}

替换函数不会将“@”替换为 $fastqfilenames 中列出的文件列表。我将“@”替换为 GLOB(0x8ab1dc)。

我做错了吗?我是否应该不使用替代品,因为这无法做到,然后在 template.txt 文件中插入文件列表($fastqfilenames)?我可以用文件内容代替 $fastqfilenames(例如 s/A/{r file.txt ...)吗?有什么建议吗?

干杯,

詹姆斯

编辑:

这让一切变得更好。

foreach (@secontrol_template) {
    s/@/$fastqfilenames/g;
    push @secontrol, $_;
}

正如这两个建议,$fastqfiles 是一个文件句柄。

替换为: open (my ($fastqfilenames), "

用这个:

my $fastqfilenames = join "\n", @fastqfiles; 

一切顺利。谢谢你们。

【问题讨论】:

    标签: perl list foreach substitution


    【解决方案1】:

    $fastqfilenames 是一个文件句柄。您必须先从文件句柄中读取信息,然后才能使用它。

    但是,您还有其他问题。

    您正在将所有文件名打印到文件中,然后从文件中读取它们。这不仅是一个有问题的设计(为什么要再次从文件中读取,因为您已经在数组中拥有了所需的内容?),它甚至都行不通:

    出于性能原因,Perl 缓冲文件 I/O。您写入文件的行实际上可能还不存在,因为 Perl 一直在等待,直到它保存了大量数据,才一次将其全部写入。

    您可以通过几种不同的方式覆盖此缓冲行为(如果您已完成写入文件句柄,则关闭文件句柄是最简单的),但正如我所说,没有理由再次重新打开文件并从中读取.

    另请注意,正则表达式替换中的 /e 选项将替换评估为 Perl 代码。在您的情况下,这不是必需的,因此您应该将其删除。

    解决方案:不要重新打开文件并阅读它,只需使用您之前在模板中替换时创建的@fastqfiles 变量。目前尚不清楚用文件名替换 @ 的确切含义。

    • 是否要将每个@ 替换为所有文件名的列表?如果是这样,您可能需要在进行替换之前以某种方式join the filenames

    • 是否要为每个文件名创建一个单独版本的模板文件?如果是这样,您需要一个内部 for 循环来遍历每个模板的每个文件名。而且您将需要除了简单替换之外的其他内容,因为替换将在第一次通过时更改原始字符串。如果您使用的是 Perl 5.16,则可以使用 /r 选项进行非破坏性替换:push(@secontrol,s/@/$file_name/gr); 否则,您应该在替换之前复制到另一个变量。

    【讨论】:

    • 我是新手,因此我的程序设计很差。这与我使用“我理解如何使用”或我想出的东西有关。 @fastqfiles 中的文件名列表可用于替换模板文件中的符号 @,但我不知道如何替换(Unix sed/awk 中的一些基本知识除外,因此尝试替换)。我不知道如何循环并将@fastqfiles 的内容保存到我的模板文件中(存储在@secontrol_template 中)。我想我可以理解使用@fastqfiles 数组的标量/列表来代替。也许,这是设计缺陷的一部分。
    【解决方案2】:

    $_ =~ s/@/$fastqfilenames/eg;

    $fastqfilenames 是文件句柄,而不是文件内容。

    无论如何,我建议使用Text::Template 模块来完成这种工作(文件文本替换)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    相关资源
    最近更新 更多