作为尝试用十进制数替换科学数字的一部分,我想将反向引用保存到字符串变量中,但它不起作用。
我的输入文件是:
,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缺乏经验
答案 0 :(得分: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 ...
我建议你尝试找一个可以处理科学记数法的模块,而不是试图破解你自己的模块。
您的代码在工作顺序中可能看起来像这样。如您所见,我在您的eval字符串周围添加了q()
,以避免在$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
之类的变量名称时执行此操作需要两倍的麻烦,因为它很容易拼写错误。
答案 1 :(得分: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
答案 2 :(得分:0)
我建议您使用Regexp::Common::number
模块的Regexp::Common
插件,它会为您找到所有实数,并允许您替换那些带有指数标记的模块
此代码显示了这个想法。使用-keep
选项使模块将每个组件放入$N
变量之一。指数标记 - e
或E
- 位于$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,
答案 3 :(得分: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
。
替换 - 原样 - 没有多大意义。
实际上,由于符号或数字都不区分大小写,因此只需在开头添加(?i)
,并避免使用E“字符类”[Ee]
:
/((?i)-?\d+(?:.\d+)?e[+-]?\d+)/