1

我是 perl 的新手。看到了很多样本​​,但在编写解决方案时遇到了问题 我有一个字符串列表,每个字符串应该替换为不同的字符串 a->a2、b->b34 等。替换列表在某个 csv 文件中。需要对目录中的所有文件递归执行此替换。可能是任何其他语言,只是认为 perl 是最快的

4

1 回答 1

4

您的问题可以分为三个步骤:

  1. 从 CSV 文件中获取搜索和替换字符串,
  2. 获取给定目录中所有文本文件的列表,包括。子目录,以及
  3. 用它们的替换替换所有出现的搜索字符串。

所以让我们倒计时,看看我们如何做到这一点:)

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

3.搜索和替换

我们将定义一个 sub searchAndReplace。它以文件名作为参数并访问外部散列。我们称这个哈希%replacements。每个键都是我们要替换的字符串,值就是替换。这“强加”了每个搜索字符串只能有一个替换的限制,但这应该看起来很自然。我将进一步假设每个文件都相当小(即适合 RAM)。

sub searchAndReplace {
  my ($filename) = @_;
  my $content = do {
    open my $file, "<", $filename or die "Cant open $filename: $!";
    local $/ = undef; # set slurp mode
    <$file>;
  };
  while(my ($string, $replacement) = each %replacements) {
    $content =~ s/\Q$string\E/$replacement/g;
  }
  open my $file, ">", $filename or die "Can't open $filename: $!";
  print $file $content; # I didn't forget the comma
  close $file;
}

这段代码非常简单,我转义了$string正则表达式内部,因此内容不会被视为模式。这种实现的副作用是可能会替换$content已经替换的字符串的一部分,但如果这是绝对必要的,可以解决这个问题。

2.遍历文件树

我们将定义一个名为anakinFileWalker. 它以文件名或目录名和searchAndReplacesub 作为参数。如果 filename 参数是一个普通文件,它会执行 searchAndReplace,如果它是一个目录,它会打开目录并在每个条目上调用它自己。

sub anakinFileWalker {
  my ($filename, $action) = @_;
  if (-d $filename) {
    opendir my $dir, $filename or die "Can't open $filename: $!";
    while (defined(my $entry = readdir $dir)) {
      next if $entry eq '.' or $entry eq '..';
      # come to the dark side of recursion
      anakinFileWalker("$filename/$entry", $action); # be sure to give full path
    }
  } else {
    # Houston, we have a plain file:
    $action->($filename);
  }
}

当然,如果你有循环符号链接,这个 sub 就会爆炸。

1. 设置%replacements

有一个不错的模块Text::CSV可以帮助您满足所有需求。只要确保%replacements满足上面的定义,但这并不难。

开始一切

准备好后%replacements,我们就做

anakinFileWalker($topDirectory, \&searchAndReplace);

应该可以工作。如果没有,这应该让您了解如何解决此类问题。

于 2012-09-02T12:29:24.400 回答