如何删除冗余字段并合并结果行

时间:2010-11-02 02:16:39

标签: regex perl sorting sed awk

我正在尝试处理纯文本文件。它基本上是一个名称和相关数字字段的索引,格式如下:

  

Nowosielski,Matthew,484,584,777
  Nowosielski,Matthew,1151
  Nunes,Paulino,116
  Nussbaum,Mike,1221,444,
  Nussbaum,Mike,156

我想在此处理

  

Nowosielski,Matthew,484,584,777,1151
  Nunes,Paulino,116
  Nussbaum,Mike,156,444,1221

正如您所看到的,这些行并不是一致的:有些可能是空格,有些是新行,有些则是逗号。实际上,我需要合并以重复的全名开头的行,在合并和保留数字字段的数字顺序时丢弃冗余名称条目。

我的直觉告诉我要学习一些快速的perl或awk,但我的技能组合对于两者都是空的。我调查了两者,经过一些搜索和阅读后找不到明确或干净的解决方案。

我的问题是:对于这项工作而言,什么是我可以有效学习并且足以完成这项任务的最佳工具?另外,根据建议的工具,是否有任何关于如何解决问题的建议?

当然,我可以手动编辑这个文件,但这不是很有趣,而且似乎是一个非常愚蠢的,对这个问题的解决方法。我正在以此任务为借口,学习一些关于文本处理的知识,因为这可能是一个很好的现有工具。

任何指针?

4 个答案:

答案 0 :(得分:4)

正如Brian所说,使用哈希表。下面删除换行符,在逗号上拆分每个记录,使用“姓氏,名字”原始形式作为哈希的键,将剩余的值推送到数组中,并使用对所述数组的引用作为上述键的值

然后它只是迭代哈希中的键/值对并相应地格式化。

修改后的解决方案 - 排序数字,省略中间名称和排序输出

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

my %merged;

while (my $record = <DATA>) {
    chomp $record;
    my ($lname, $fname, @stuff) = split /[, ]+/, $record;
    push @{ $merged{"$lname, $fname"} }, grep { m/^\d+$/; } @stuff;
}

foreach my $name (sort keys %merged) {
    print $name, ", ", join( ', ', sort { $a <=> $b } @{$merged{$name}}), "\n";
}

__DATA__
Nowosielski, Matthew, 484, 584, 777
Nowosielski, Matthew, 1151
Nunes, Paulino, 116
Nussbaum, Mike, 1221, 444,
Nussbaum, Mike, 156
Nowosielski, Matthew, Kimball, 485, 684, 277

修改后的输出

Nowosielski, Matthew, 277, 484, 485, 584, 684, 777, 1151
Nunes, Paulino, 116
Nussbaum, Mike, 156, 444, 1221

原始解决方案

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

my %merged;

while (my $record = <DATA>) {
    chomp $record;
    my ($lname, $fname, @stuff) = split /,/, $record;

    push @{ $merged{"$lname, $fname"} }, @stuff;
}

while (my ($name, $stuff) = each %merged) {
    print $name, join( ',', @$stuff), "\n"; 
}

__DATA__
Nowosielski, Matthew, 484, 584, 777
Nowosielski, Matthew, 1151
Nunes, Paulino, 116
Nussbaum, Mike, 1221, 444,
Nussbaum, Mike, 156

答案 1 :(得分:2)

以此为借口学习,我会写一个快速的python脚本。

使用字符串作为键和值,使自己成为字典(地图)。读一行,抓住名字。在字典中查找名称。如果它在那里,则将新数字附加到字典条目的末尾。当您阅读整个文件时,遍历字典并打印出键和值。

答案 2 :(得分:1)

要干净利落地完成这项工作,您需要一种具有关联数组的语言(Perl - 哈希; Python - 词典; Awk - 关联数组)。这排除了sed(和C)。

awk

awk '{ for (i = 3; i <= NF; i++) {names[$1, $2] = names[$1, $2] " " $i } }
     END { for (name in names) { printf "%s: %s\n", name, names[name]; } }'

您可能更喜欢将逗号指定为带有“-F,”的字段分隔符。

额外的要求 - 按顺序排序数字并处理中间名称 - 在awk中处理比perl更加频繁;有了额外的要求,我会选择perl而不是awk。 (请注意,GNU Awk具有内置函数asortasorti来排序数组,但我不确定您是否可以names[$1,$2]在{{1}中识别整数数组我觉得Perl比Python更流畅 - 但是Python无疑也可以做Perl处理的事情。

答案 3 :(得分:0)

尝试使用AWK

#!/usr/bin/awk -f
$1 == lastOne && $2 == lastTwo { $1=""; $2=""; printf ", %s", $0 ;lastOne=$1; lastTwo=$2 }
$1 != lastOne && $2 != lastTwo { printf "\n%s", $0 ;lastOne=$1; lastTwo=$2 }
END {printf "\n" }

此脚本假设数据按前两个字段排序......