使用任何可行的方法(PERL,SED,AWK)从文件行中提取信息到列中

路易斯·卡塞雷斯

也许我对于perl / awk / sed来说太老了,还太年轻而无法停止编程。这是我需要解决的问题:

我在TXT文件中有这样的信息:

Name:
Name 1
Phone:
1111111
Email:
some@email1
DoentMatterInfo1:
whatever1
=
Name:
Name 2
Phone:
22222222
DoentMatterInfo2:
whatever2
Email:
some@email2
=
Name:
Name 3
DoentMatterInfo3:
whatever2
Email:
some@email3
=

请注意,所需信息在下一行中,有一个记录分隔符(=),非常重要,有些记录并没有全部信息,但可能有我们不想要的信息。

因此,挑战在于如何在输出中提取所需的信息(如果存在):

Name 1 ; 111111 ; some@email1
Name 2 ; 222222 ; some@email2
Name 3 ; ; some@email3

我尝试过的方法虽然有点奏效,但仍然不是我想要的。

1.使用PERL

使用Perl,我得到了重要的字段:

while (<>) {

    if ($_ =~ /Name/) {
        print "=\n". scalar <>;

    }    
    if ($_ =~ /Email/) {
        print "; ". scalar <>;

    } 
    if ($_ =~ /Phone/) {
        print "; ". scalar <>;

    } 

}

我有一个类似的文件:

Name 1
; 1111111
; some@email1
=
Name 2
; 22222222
; some@email2
=
Name:
Name 3
; some@email3
=

现在使用sed将每条记录放在一行中:

SED使用SED,此命令替换换行,将信息放在一行中:sed ':a;N;$!ba;s/\n//g' input.txt > out1.txt

然后返回换行符:

sed 's/|=|/\n/g' out1.txt > out2.txt

所以我得到了一个文件,每行都有信息:

Name 1 ; 1111111 ; some@email1
Name 2 ; 22222222 ; some@email2
Name 3 ; some@email3

仍然不是我想从编码中得到的东西。我想要更好的东西,例如能够为丢失的电话填充空间,因此第二列可以始终是phone列。你明白了吗?

如您所见,不管使用的是Perl,AWk还是SED,寻找解决方案的目的都在于。我正在尝试Perl哈希...

提前致谢!!

出租

这是一个Perl解决方案,需要并尝试

use warnings;
use strict;
use feature 'say';

my @fields = qw(Name Phone Email);  # fields to process

my $re_fields = join '|', map { quotemeta } @fields;

my %record;

while (<>) { 
    if (/^\s*($re_fields):/) { 
        chomp($record{$1} = <>);
    }
    elsif (/^\s*=/) { 
        say join ';', map { $record{$_} // '' } @fields;
        %record = (); 
    }   
}

输入准备在数组中@fields这是唯一列出这些名称的地方,因此,如果需要在处理中添加更多字段,只需在此处添加即可。在中,还准备了用于匹配这些字段中任何一个的正则表达式模式$re_fields

然后,我们使用<>operator逐行读取在命令行上提交的所有文件

if条件捕获期望的关键字(如果存在)。在主体中,我们读取下一行的值并将其存储为键,该键即为捕获的关键字(不必知道哪个)。

在从=记录开始的一行中打印(正确显示给定的样本文件)。我没有为缺少的字段(没有空格)和周围没有多余的空格放任何东西;根据需要调整输出格式。


为了完整地收集记录并在以后进行进一步处理(或仅打印),请将它们添加到合适的数据结构中,而不是打印。选择哪种存储取决于预想的处理类型。最简单的方法是将每个输出记录的字符串添加到数组中

my (@records, %record);

while (<>) {
    ...
    elsif (/^\s*=/) { 
        push @records, join ';', map { $record{$_} // '' } @fields;
        %record = (); 
    }   
}

现在@records已为所有记录准备好了字符串,可以将其打印为

say for @records;

但是,如果需要更多的处理,则最好将数组副本存储%record为哈希引用,以便以后可以更轻松地操作各个组件。

my (@records, %record);

while (<>) {
    ...
    elsif (/^\s*=/) { 
        # Add a key to the hash for any fields that are missing
        $record{$_} //= ''  for @fields;
        push @records, { %record };
        %record = (); 
    }   
}

我为可能缺少的字段添加了一个键,以便哈希引用具有所有期望的键,并为其分配一个空字符串。另一种选择是分配undef

现在,您可以按以下方式访问每个记录中的各个字段:

foreach my $rec (@records) { 
    foreach my $fld (sort keys %$rec) {
        say "$fld -> $rec->{$fld}"
    }
}

或当然只使用Data::Dumper诸如此类打印整个内容

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章