【问题标题】:How to use Perl to perform substitutions based on calculations?如何使用 Perl 进行基于计算的替换?
【发布时间】:2011-03-10 16:24:01
【问题描述】:

我正在尝试编写一个 perl 脚本来搜索文本文件,查找所有十进制数字,并通过一些缩放因子对其进行修改。到目前为止,我已经成功地用正则表达式提取了数字:

open(INPUT, $inputPath) or die "$inputPath cannot be opened.";

while ($thisLine = <INPUT>) {
  while ($thisLine =~ m/(-*\d+\.\d+)/g) {
    if(defined($1)) { 
      $new = $scalingFactor*$1;
      print $new."\n";
    }
  }
}

close (INPUT);

但是,我还没有弄清楚如何将新值重新插入到文件中。我尝试使用s/(-*\d+.\d+)/$scalingFactor*$1/g 进行替换,但当然这插入了$scalingFactor 的字符串表示,而不是评估表达式。

我是 perl 新手,因此我们将不胜感激。提前致谢,

-丹

编辑:解决方案(基于 Roman 的回复)

while ($thisLine = <INPUT>) {
  $thisLine =~ s/(-*\d+\.\d+)/$scalingFactor*$1/ge;
  prinf OUTPUT $thisLine;
}

另外,肖恩的解决方案对我也很有效。谢谢大家!

【问题讨论】:

  • 一般说明:使用三个参数openlike,open(my $fh, '&lt;', "input.txt") or die $!;
  • @Nikhil Jain 谢谢,我会改变的。

标签: regex perl file-io


【解决方案1】:
s/(-*\d+.\d+)/$scalingFactor*$1/ge

(最后通知e

【讨论】:

  • 谢谢。这似乎正确地修改了数字,但不幸的是它也导致了一个无限循环,其中数字被一遍又一遍地缩放。想法?
  • @Dan:尝试转义正则表达式中的点,即s/(-*\d+\.\d+)/$scalingFactor*$1/ge
  • 谢谢,不转义点绝对是一个错误。然而,这似乎不是造成无限循环的原因。基本上,只要乘以$scalingFactor 得到一个整数,循环就会终止。但只要结果有小数余数,就会再次缩放。
  • @Dan:您能发布一个完整的示例(包括示例输入)吗?我无法重现您描述的行为。
  • @Dan: 啊,所以是你的内部while 循环永远循环。你就不能放下吗? g 替换标志已经确保您将替换所有出现的位置。
【解决方案2】:

这是一个可以完成这项工作的独立子例程。它使用特殊变量$^I,它激活了Perl 的就地编辑功能。 (有关$^I 的更多信息,请参见“perlvar”手册页,有关-i 命令行开关的信息,请参见“perlrun”手册页,该开关可打开就地编辑。)

use strict;  # Always.

sub scale_numbers_in_file_by_factor {
    my ($path, $scaling_factor) = @_;
    local @ARGV = ($path);
    local $^I = '.bak';
    while (<>) {
        s/ ( -? \d+ \. \d+ ) / $scaling_factor * $1 /gex;
        print;
    }
}

scale_numbers_in_file_by_factor('my-file.txt', .1);

将通过将'.bak' 附加到原始文件名来制作备份文件。如果您不想备份,请将上面的 '.bak' 更改为 ''

您可能想要调整您的数字识别正则表达式。如所写,它不会匹配没有尾随小数点和至少一位数字的数字。我认为您还希望-? 匹配可选的减号,而不是-*,它将匹配任意数量的减号。对具有多个前导减号的字符串执行算术几乎肯定不会达到您想要的效果。

【讨论】:

  • 谢谢!我会试试这个。 -* 应该更改为 -?,这当然也是正确的。
猜你喜欢
  • 2020-09-13
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多