1

作为尝试用十进制数替换科学数字的一部分,我想将反向引用保存到字符串变量中,但它不起作用。

我的输入文件是:

,8E-6,
,-11.78E-16,
,-17e+7,

然后我运行以下命令:

open FILE, "+<C:/Perl/input.txt" or die $!;
open(OUTPUT, "+>C:/Perl/output.txt") or die;

while (my $lines = <FILE>){

  $find = "(?:,)(-?)(0|[1-9][0-9]*)(\.)?([0-9]*)?([eE])([+\-]?)([0-9]+)(?:,)";
  $noofzeroesbeforecomma = eval("$7-length($4)");
  $replace = '"foo $noofzeroesbeforecomma bar"';

  $lines =~ s/$find/$replace/eeg;
  print (OUTPUT $lines);
}

close(FILE);

我明白了

foo  bar
foo  bar
foo  bar

我本来期望的地方

foo 6 bar
foo 14 bar
foo 7 bar

$noofzeroesbeforecomma似乎是空的或不存在的。

即使进行了以下调整,我也会得到一个空的结果

$noofzeroesbeforecomma = $2;

只有$2直接插入替换字符串才能给我一些东西(不幸的是,这不是我想要的)。

任何人都可以帮忙吗?

我在 64 位 Windows 7 机器上运行 Strawberry Perl (5.16.1.1-64bit),并且对 Perl 非常缺乏经验

4

4 回答 4

1

你的主要问题是没有使用

use strict;
use warnings;

warnings会告诉你的

Use of uninitialized value $7 in concatenation (.) or string at ...
Use of uninitialized value $4 in concatenation (.) or string at ...

我建议您尝试找到一个可以处理科学记数法的模块,而不是尝试破解您自己的模块。

您的代码按正常工作顺序可能看起来像这样。如您所见,我q()在您的 eval 字符串周围放置了一个,以避免它在之前被评估$7$4存在。我还删除了 eval 本身,因为虽然 eval 上的双重 eval 有点过分。

use strict;
use warnings;

while (my $lines = <DATA>) {
    my $find="(?:,)(-?)(0|[1-9][0-9]*)(\.)?([0-9]*)?([eE])([+\-]?)([0-9]+)(?:,)";
    my $noof = q|$7-length($4)|;
    $lines =~ s/$find/$noof/eeg;
    print $lines;
}


__DATA__
,8E-6,
,-11.78E-16,
,-17e+7,

输出:

6
14
7

作为旁注,不使用strict是自找麻烦。在使用变量名时这样做$noofzeroesbeforecomma会带来两倍的麻烦,因为很容易打错字。

于 2012-09-07T14:37:36.013 回答
0

我建议您使用该模块的插件,该Regexp::Common::number插件Regexp::Common将为您找到所有实数并允许您替换具有指数标记的那些

这段代码显示了这个想法。使用该-keep选项使模块将每个组件放入其中一个$N变量中。指数标记 -eE- 在 中$7,因此可以根据是否存在来转换数字

use strict;
use warnings;

use Regexp::Common;

my $real_re = $RE{num}{real}{-keep};

while (<>) {
  s/$real_re/ $7 ? sprintf '%.20f', $1 : $1 /eg;
  print;
}

输出

给定您的示例输入,此代码将生成以下内容。可以使用替换中的附加代码进一步整理这些值

,0.00000800000000000000,
,-0.00000000000000117800,
,-170000000.00000000000000000000,
于 2012-09-07T15:31:24.033 回答
0

这不是关于反向引用,而是原始问题,将数字从科学记数法转换。我敢肯定在某些情况下会失败:

#!/usr/bin/env perl

use strict;
use warnings;
use bignum;

for (<DATA>) {
    next unless /([+-]?\d+(?:\.\d+)?)[Ee]([+-]\d+)/;
    print $1 * 10 ** $2 . "\n";
}

__DATA__
,8E-6,
,-11.78E-16,
,-17e+7,

输出:

0.000008
-0.000000000000001178
-170000000
于 2012-09-07T15:26:43.600 回答
0

问题是 Perl 可以处理所有这些类型的表达式。由于 Perl 中的标准数据项是字符串,因此您只需捕获表达式即可使用它。所以,取这个表达式:

/(-?\d+(?:.\d+)?[Ee][+-]?\d+)/

从周围的文本中提取它并使用sprintf它来格式化它,就像 Borodin 展示的那样。

但是,如果它可以帮助您更好地了解您尝试做的事情,那么效果会更好

my ( $whole, $frac, $expon )
    = $line =~ m/(?:,)-?(0|[1-9]\d*)(?:\.(\d*))?[eE]([+\-]?\d+)(?:,)/
    ;
my $num = $expon - length( $frac );
  • 如果你打算用它做算术,为什么不用指数来捕捉符号呢

  • 最好命名您的捕获并eval在不需要时避开。

  • 替换——按原样——没有多大意义。

  • 真的,因为符号或数字都不区分大小写,所以只需将 a(?i)放在开头,并避免 E "character class" [Ee]

    /((?i)-?\d+(?:.\d+)?e[+-]?\d+)/
    
于 2012-09-07T20:35:26.123 回答