【问题标题】:Perl Function Extracting Data with Specified Start Columns and LengthPerl 函数提取具有指定起始列和长度的数据
【发布时间】:2013-02-26 16:38:34
【问题描述】:

我正在尝试编写一个代码,从文件 A 中提取数据并仅将具有指定起点和终点的列数据粘贴到文件 B 中。到目前为止,我只能成功地将所有数据从 A 复制到 B -但我没有得到任何过滤掉列的地方。我试过研究 splice 和 grep 无济于事。没有Perl经验。数据没有列标题。 示例:数据实际上长达数千行 - 无法将数据插入函数

1. AAA 565 u8y 221
2. ABC 454 9u8 352
3. ADH 115 i98 544
4. AKS 352 87y 454
5. GJS 154 i9k 141

我希望将第 3 列的所有唯一值(开始:8 长度:3)复制到文件 B 中。我尝试了 How to extract a particular column of data in Perl? 中提供的解决方案,但无济于事。

感谢任何提示或帮助!

 #!/usr/bin/perl
use strict;
use warnings;

#use Cwd qw(abs_path);

#my $dir = '/home/
#$dir = abd_path($dir);
my $filename = "filea.txt";
my $newfilename = "fileb.txt"; 

#Open file to read raw data
open (DATA1, "<$filename") or die "Couldn't open $filename: $!";

#Open new file to copy desired columns
open (DATA2, ">$newfilename") or die "Couldn't open $newfilename: $!";

#Copy data from original to new file

while (<DATA1>) {
    #DATA2=splice(DATA1, 0,5);
    print DATA2 $_;
    my @fifth_column = map{(split)[1]} split /\n/, $newfilename;    
}

【问题讨论】:

    标签: perl extract


    【解决方案1】:

    如果我理解正确的话,你可以使用一个相当简单的脚本。

    use strict;
    use warnings;
    
    my %seen;
    while (<DATA>) {
        my $str = substr($_, 8, 3);   # the string you seek
        unless ($seen{$str}++) {      # if it is not seen before
            print "$str\n";           # ...print it
        }
    }
    
    __DATA__
    AAA 565 u8y 221
    AAA 565 u8y 221
    ABC 454 9u8 352
    ADH 115 i98 544
    AKS 352 87y 454
    GJS 154 i9k 141
    

    输出:

    u8y
    9u8
    i98
    87y
    i9k
    

    DATA 文件句柄在这里用于演示。我还在数据中添加了一个副本来演示重复数据删除。如果您将&lt;DATA&gt; 更改为&lt;&gt;,您可以像这样简单地使用脚本:

    perl script.pl filea.txt > fileb.txt
    

    注意,这依赖于您的数据是固定宽度,这意味着如果您的字段没有对齐,您的输出将被损坏。

    另请注意,这只是一个简单的单行的完整版本,如下所示:

    perl -nlwe '$x=substr($_,8,3); print $x unless $seen{$x}++' filea.txt > fileb.txt
    

    【讨论】:

    • 单线效果很好!非常感谢你告诉我这个选项!它确实吐出了以下警告 - 即使它给了我正确的输出。 @TLP 名称“main::seen”仅使用一次:-e 第 1 行可能存在拼写错误。
    • 意在补充——我并不十分担心这个警告......只是一个仅供参考的@TLP
    • @todayspresent 该警告不相关。它存在只是因为我们实际上一次做两件事,unless $seen{$x}++ 真的是 unless $seen{$x}; $seen{$x}++; 的缩写。加上单行不使用严格的事实,所以我们不声明变量。如果您认为您的问题已得到解答,您可以通过单击旁边的复选标记来接受答案。
    • 谢谢!在大多数情况下,它得到了回答。 @TLP 使用代码时,它包含一些不应该包含的值。例如,在上面的输出中 - 如果我想省略前面带有“i”的那些。有没有办法让unless $seen{$x}++ 也与unless substr($_,0,1) ne 'i' 一起工作?让我知道是否需要将此作为不同的问题输入。谢谢!
    • @todayspresent 好吧,你可以这样做 if (!/^i/ &amp;&amp; !$seen{$_}++) 假设我得到了所有的否定,但你明白了。
    【解决方案2】:

    看看以下 Perl 命令:

    • split:这允许您将一行数据拆分为一个数组:

    例子:

    while ( my $line = <$input_fh> ) {
        my @items = split /\s+/, $line;   #Columns are separated by spaces or tabs
        my $third_column = $items[2];  #The column you want;
        blah...blah...blah;
    }
    
    • substr:这允许您指定列信息的子字符串。如果您的列由制表符分隔,这可能没有那么有用。对于大多数非 Perl 开发人员来说,这是他们尝试的第一种方法。不过,我建议使用split

    有一个 Perl 技巧可以确保您的数据是唯一的:使用散列来存储您的信息。在散列中查找数据很快,如果您已经看过该数据,可以使用exists 函数快速查找。结合split:

    use strict;
    use warnings;
    use autodie;
    
    use constants {
        INPUT_FILE  => "filea.txt",
        OUTPUT_FILE => "fileb.txt",
    };
    
    open my $input_fh, "<", INPUT_FILE;
    open my $output_fh ">", OUTPUT_FILE;
    
    my %unique_columns;
    while ( my $line = <$input_fh> ) {
        my @items = split /\s+/, $line;   #Columns are separated by spaces or tabs
        my $third_column = $items[2];  #The column you want;
        if ( not exists $unique_columns{$third_column} ) {
            $unique_columns{$third_column} = 1;
            print {$output_fh} "$third_column\n";
        }
    }
    close $output_fh;
    

    %unique_columns 哈希跟踪可查看您之前是否在文件的第三列中看到过该数据。将每个单独的键设置为等于什么都没关系。但是,我建议将其设置为非零值或空白值,因为如果您这样做:

    if ( $unique_columns{$data} )
    

    而不是

    if ( exists $unique_columns{$data} )
    

    只要$unique_columns{$data} 的值不为零或空白,您的程序仍然可以运行,否则会失败。

    【讨论】:

    • 这很有帮助-我将不得不研究使用哪些行来替换“blahs”和“yaddas”-感谢您的解释! :-) @David W.
    • yaddas 将是:print DATA2 $third_column;
    • @todayspresent - 我已经更新了我的答案以显示整个程序。
    • 啊,明白了!谢谢! @大卫 W.
    【解决方案3】:

    当谈到固定长度时,没有什么比打包/解包更好的了,学习本教程,它将让您的生活更轻松,这项工作变得轻而易举。

    http://linux.die.net/man/1/perlpacktut

    【讨论】:

    • 模板(A4)*应该unpack你的字符串。
    猜你喜欢
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 2016-02-06
    • 2017-12-26
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多