【问题标题】:Converting string to number “Argument isn’t number error”将字符串转换为数字“参数不是数字错误”
【发布时间】:2016-11-01 16:52:10
【问题描述】:

我正在解析制表符分隔的文件。有几列没有被识别为数字,即使它们显然是数字。当我尝试总结这些值时,会显示错误:Argument ""97"" isn't numeric in addition (+) 并且 Perl 返回 0。

我尝试过使用Scalar::Util qw(looks_like_number);,但它产生了相同的结果“0”。还有什么我可以尝试的吗?

代码如下:

open my $out_fh, '>', $final_variants or die qq{Unable to open "$final_variants" for output: $!};

open my $in_fh, '<', $tsv_file_new
            or die qq{Unable to open "$tsv_file_new" for input: $!};

while ( <$in_fh> ) {

        my @fields = split;

        my $forward_reference = $fields[67];
        my $reverse_reference = $fields[68];
        my $forward_variant_reads = $fields[77];
        my $reverse_variant_reads = $fields[78];

        my $total_reads = (looks_like_number($forward_reference))
                + (looks_like_number($reverse_reference))
                + (looks_like_number($forward_variant_reads))
                + (looks_like_number($reverse_variant_reads));

        my $current_final_line = $headerline . "\t"
                    . $forward_reference . "\t"
                    . $reverse_reference . "\t"
                    . $forward_variant_reads . "\t"
                    . $reverse_variant_reads . "\t"
                    . $total_reads . "\t";

        print $out_fh $current_final_line, "\n";
}

【问题讨论】:

  • "97" 确实不像一个数字,不像97。听起来您的字段中有引号。

标签: perl parsing


【解决方案1】:

您的错误消息已经说明:参数“97”不是数字。当 number 实际上是一个字符串 被引号 (") 包围时,就会发生这种情况, 像这样:

my $num = '"42"';
my $sum = $num + 1;

这给出了:

参数“42”不是数字加法 (+) 在...

试着去掉你数字中的引号

$num =~ s/"//g;

【讨论】:

  • 作为替代方案 - 模式匹配数字部分:my ($num) = $str =~ m/(\d+)/;
  • @Sobrique 好得多。像我一样去掉引号是快速的'n'dirty大锤方法。
【解决方案2】:

该错误是由于额外的引号引起的,但我首先要提到一个编码问题。通过 looks_like_number($var) + ... 添加值是一个错误。 looks_like_number,来自Scalar::Util

如果 perl 认为 EXPR 是一个数字,则返回 true。

它用于测试变量是否为数字。它返回一个零或一个大的正整数。因此,您需要先测试哪些是数字,例如通过 grep 过滤,然后才将它们用作数字。

正如answer by perlduck 中所解释的,很明显有额外的引用。但是,我会小心删除所有引号,因为您可能会暴露一些确实不是数字的东西。此外,如果涉及其他处理,可能需要 inside 字符串的引号。

我仍然会最终通过looks_like_number 测试变量,清除封闭引号,并组装那些数字。也许

use List::Util qw(sum);
# Remove extra (leading and trailing) quotes, for example
my @references   = map { s/^"//; s/"$//; $_ } ($forward_reference, ...);
my @numeric_refs = grep { looks_like_number($_) } @references;
my $total_reads  = sum @numeric_refs;

这里使用了来自核心List::Util 模块的sum。如果除了求和之外什么都不做(因此没有很好地使用这些中间数组),上述所有内容都可以在一个语句中串起来,因为每个操作都需要并返回一个列表

my $total_reads  = sum
    grep { looks_like_number($_) }
    map { s/^"//; s/"$//; $_ } $forward_reference, ...;

更好的是,您可以使用Text::CSV 解析制表符分隔的文件,它可以很好地处理引号。

use warnings;
use strict;
use Text::CSV;
use List::Util qw(sum);

my $csv = Text::CSV->new( 
    { binary => 1, sep_char => "\t", allow_loose_quotes => 1 } 
) or die "Cannot use CSV: " . Text::CSV->error_diag ();

my $file = $tsv_file_new;
open my $fh, '<', $file  or die "Can't open $file: $!";

while (my $row = $csv->getline($fh)) {
    my @fields = @$row;
    # process. quotes around fields are gone
    # ...
    my @references = ($forward_reference, ...);
    my $total_reads = sum grep { looks_like_number($_) } @references;
}
$csv->eof or $csv->error_diag();
close $fh;

【讨论】:

    猜你喜欢
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 2012-01-10
    • 2011-12-13
    • 2020-06-23
    • 2014-10-21
    相关资源
    最近更新 更多