【问题标题】:Perl: output still only one linePerl:输出仍然只有一行
【发布时间】:2016-09-06 01:16:08
【问题描述】:

这是同一个项目的第三个问题: 我试图在 2,000 多个子目录中从“pairsAngles.txt”中提取字符串“Distance:”;子目录的名称是从 csv 文件中获取的。 将 eol => $/ 传递给 Text::CSV_XS->new AND 使用 $csv->say 后,输出仍然是一行...

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Find;
use Text::CSV_XS;

my @pairs=();
my @result=();
my $c1;
my $in;
my $out;
my $pairs;
my $dist = "";
my $dir = "/home/avabelieve/aaPROJECT/helicalPair_ax/selectedPairs/renumberedPdb/clusterPairs-1.25-12-05_windows.12.resle3.2A.RMSD1.3/oligomerAngle";
my $cluster = "clst1.csv";
open ($in, $cluster) || die "cannot open \"$cluster\": $!";
my $cU = "clst1Updated.csv";
open ($out, ">$cU") || die "cannot open '$cU' $!";
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1, eol => $/ });

while ($c1 = <$in>) {
    chomp $c1;
    push @pairs, $c1;
}

foreach $c1 (@pairs) {
    find (\&Matches, "$dir/$c1");
    sub Matches {
        open ($pairs, "pairsAngles.txt") or die "$!";

        while (my $dist = <$pairs>) {

            if ($dist =~ m/Distance: /) {                    
                chomp $dist;
                push (@result, "$dist\n");
            }               

        } 
    }
}
chdir "..";

if (not $csv->eof) {
    $csv->error_diag();
} 

$csv->say ($out, [@pairs, @result]);
close $out or die "$!";

【问题讨论】:

  • 您可能已经注意到我一直在编辑您的代码以更改支撑和缩进。大括号和缩进的位置对于使代码可读非常重要,特别是对于您的问题,了解哪些代码在哪个循环中。考虑采用这种更常见的支撑样式。
  • 在这一点上,您感觉就像在移动代码,直到某些东西在没有完全理解发生了什么的情况下工作。而且我们不明白你想要完成什么,所以我们能做的只有这么多。那么你为什么不解释你在这里想要完成的事情呢?给我们具体的输入,例如一些简短的 CSV 数据、一个小的示例目录树以及您期望的输出。
  • 这是我看到的。您在@pairs 中获得目录。对于每个文件中的一个文件,您获取$dist 并将其添加到@results。一个猜测:你想写出一个包含行directory | dist-line 的文件。问题:如果$dist 被多次找到或在文件中找不到怎么办?然后@pairs@results长度不匹配,不能简单的写出文件。您必须在循环中添加一些处理,将多个或零匹配与它们发生的目录相关联。如果只能有 一个 匹配项,则最好以不同的方式编写代码。这有意义吗?
  • 既然这演变成一个新问题,我建议你mark answers here accordingly,所以未来的访问者很清楚这个问题是如何解决的。如果此处提出的特定问题仍有问题,请发布反馈。

标签: regex perl csv text format


【解决方案1】:

我不知道您想如何在输出中组合 @pairs@result,而是根据 Text::CSV_XS docs 中的概要将整个数组写入您需要的电子表格中

 $csv->say ($fh, $_) for @rows;

让我们知道如何在输出中配对 @pairs@result 以了解更多详情。


澄清:写入的行应该有一个用于目录的单元格和另一个用于相应匹配行的单元格,我们确定每个文件中都有一个这样的匹配项。那么

if (@pairs != @result) {
    die "Mismatching lengths: directory " . scalar(@pairs) .
        " vs matches " . scalar(@result);
}
for my $i (0..$#pairs) {
    $csv->say($out, [$pairs[$i], $result[$i]]);
} 

请注意@pairs != @result 确实防范所有可能的意外不匹配,它更多的是在代码中包含更严格的检查的提示。 (例如,一个文件中可能不匹配,但另一个文件中有两个,并且数组最终将具有相同的长度。)检查@result 的添加位置将测试确实存在一个匹配项。


一个注释。某处的代码删除了带有chomp 的新行,但随后又将其放回了\n

chomp $dist;
push (@result, "$dist\n");

不需要\n,也不需要""——只需push @result, $dist;。至于换行符,要么用chomp 删除它,要么留下它(删除chomp)。我不明白为什么进入电子表格的字符串需要换行符。

【讨论】:

  • 我只需要在最终的 csv 输出中包含两列:第一列包含来自@pairs 的所有子目录名称,第二列包含来自@results 的距离...我的方法有误吗?
  • @AvaXue 好的,谢谢。请在您的问题下方查看我的评论 - 您可以在一个文件中有多个匹配 $dist,还是可能没有?如果一个文件有多个$dist 行,您希望如何在电子表格中包含它?在该行中,您将有一个带有目录名称的单元格,然后......多个$dist 去哪里?或者你想要一个行,即使是同一个目录?如果每个文件只能有一个这样的行,您确定确定吗?我不确定我是否解释得很好——你知道我的意思吗?
  • 是的,我很确定在每个子目录下的每个 pairsAngles.txt 中总是只有一个匹配 $dist
  • @AvaXue 好的。如果您“非常确定”,那很简单,我会尽快添加。我很小心,因为如果一个额外的(或丢失的)以某种方式潜入,使用两个数组并假设长度相等可能会导致不良行为。我会为此添加一个测试。
  • 来自 linux 终端:Mismatching lengths of directory/match arrays at ./test2.pl line 42, &lt;$subdir&gt; line 160. 第 42 行:csv-&gt;say($out, [$pairs[$i], $result[$i]]); 我认为问题来自 foreach 或 while...
【解决方案2】:

由于$csv-&gt;say 位于程序的末尾,并且它不在循环中,所以它只会打印一行。它将有每一对和每一个结果。

$csv->say ($out, [@pairs, @result]);

我不确定您要完成什么,但您可能希望在循环中打印结果。

【讨论】:

    猜你喜欢
    • 2015-06-18
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多