0

我在 CSV 文件中有数据(IP 地址),该文件将是第 9-13 列。如果其他列中没有值,则默认情况下它应该只打印第 9 列中的内容。有一个输出文件将打印一组值和第 9 列的值(如果有值,则通过 13存在)与静态值连接以创建别名值。我的问题是,你将如何有效地做到这一点?我有这个有效的代码:

my $alias0= "ComponentAliases=['ComputerSystem:$columns[9]'];\n";
my $alias1= "ComponentAliases=['ComputerSystem:$columns[9]','ComputerSystem:$columns[10]'];\n";
my $alias2= "ComponentAliases=['ComputerSystem:$columns[9]','ComputerSystem:$columns[10]','ComputerSystem:$columns[11]'];\n";


        print BAROC "ComputerSystem;\n";
        if(($columns[11] != '')&&($columns[10] != '')) {  print BAROC $alias2 }
        elsif(($columns[11] == '')&&($columns[10] != '')) {  print BAROC $alias1 }
        elsif(($columns[11] == '')&&($columns[10] == '')) { print BAROC $alias0 }

这可以做我想做的事情,但是CSV文件有可能在第9-13或9-11列等中有值。很容易我认为静态编写它会很好,但我想做它有效地理解并始终应用最佳实践。我是编写 Perl 脚本的新手,但一直被它吸引来解决工作中的问题。建议?

这是输出,顺便说一句:

ComponentAliases=['ComputerSystem:10.1.0.225','ComputerSystem:10.200.252.77','ComputerSystem:10.100.252.77'];
4

3 回答 3

1
#!/usr/bin/env perl

use strict;
use warnings;

use Text::CSV_XS;

my $csv_in = Text::CSV_XS->new
    or die Text::CSV_XS->error_diag;

my $csv_out = Text::CSV_XS->new({
    always_quote => 1,
    quote_char => q{'},
}) or die Text::CSV_XS->error_diag;

while (my $row = $csv_in->getline(\*DATA)) {
    my @aliases = map "ComputerSystem:$_",
                  grep defined && length, @$row[9 .. 13];
    if ($csv_out->combine(@aliases)) {
        printf "ComponentAliases=[%s];\n", $csv_out->string;
    }
}

__DATA__
0,1,2,3,4,5,6,7,8,10.1.0.225,10.200.252.77,,,,,,,
0,1,2,3,4,5,6,7,8,10.1.0.225,10.200.252.77,10.100.252.77,,,,,

输出:

C:\温度> gn
ComponentAliases=['ComputerSystem:10.1.0.225','ComputerSystem:10.200.252.77'];
ComponentAliases=['ComputerSystem:10.1.0.225','ComputerSystem:10.200.252.77','Co
电脑系统:10.100.252.77'];
于 2013-03-20T22:05:01.800 回答
1

Efficiently now 意味着可维护的。尝试保存一两个命令不会为您节省太多时间。事实上,如果编译器无法弄清楚你在做什么,它实际上可能会使程序效率更低。

重要的是可读性。摆脱这些$alias东西。它只是让你更难看到你的代码在做什么,你最终可能会遇到各种各样的副作用来做这样的事情。

缺少空白也使您的代码更难弄清楚。重新格式化您的代码后,我立即发现了一个错误。你这样做了:

if ( ($columns[11] != '') && ($columns[10] != '') )

但是,这是一个字符串比较。你需要这样做:

if ( ( $columns[11] ne '' ) && ( $columns[10] ne '' ) ) {

或者,您可以进一步简化它:

if ( not $column[10] and not $column[11] ) {

这使您非常清楚您要查找的内容,并且无论列是否包含数字零、空字符串或未定义,都可以使用。

此代码片段正在使用您的逻辑,但我利用了print不会\n在字符串末尾自动添加 a 的事实。我只是继续建立在这条线上:

if ( $columns[9] ) {
    print BAROC "ComputerSystem;\n";
    print BAROC "ComponentAliases=['ComputerSystem:$columns[9]'";

    if ( $columns[10] ) {
         print BAROC ",ComputerSystem:$columns[10]";
    }
    if ( $columns[11] )  {
        print BAROC ",ComputerSystem:$columns[11]";
    }
    print BAROC "];\n";
}

您提到如果这些列中有数据,您可能需要第 9 到 13 列。为什么不使用循环?

if ( $#columns >= 9 ) {    #There are at least nine columns
    print BAROC "ComputerSystem;\n";
    print BAROC "ComponentAliases=[ComputerSystem:$columns[9]";

    for my $column ( (10..$#columns) ) {
       last if not $column[$column];
       print BAROC ",ComputerSystem:$columns[$columns];
    }
    print BAROC "];\n";
}

如果有更多时间,我相信我可以进一步清理逻辑。但是,无论有 9、10、11 还是 43 列数据,这都可以。

于 2013-03-20T23:05:36.547 回答
0

一个班轮(不是那么优雅,但不知何故我喜欢它):

print "ComponentAliases=[".join(",",map {"'ComputerSystem:$_'"} grep {$_ ne ""} @columns[9-13])."]\n";

或者,如果您更喜欢以更易于理解的方式使用相同的代码:

print(  
        "ComponentAliases=[",
        join(
            ",",
            map(    
                "'ComputerSystem:$_'",
                grep (
                        $_ ne "",
                        @columns[9-13]
                     )
               )
            ),  
        "]\n"
     );  
于 2013-03-20T21:09:52.847 回答