2012-04-27 63 views
-1

我有一个制表符分隔的文件,例如从制表符分隔的文件访问数据

ID NAME  FAMILYTAG  EFFECT 
001 John  Black   Positive 
002 Kate  Rhodes,Mich Positive 
003 Aaron  Sunders  Negative 
004 Shirley Rhodes  Negative 
005 Dexter Sunders,Hark Positive 

我想输入这个文件(实际上更大的是),并读取某一名称,例如Kate 。我希望脚本识别其家庭标记,即它包含Rhodes,然后输出其他家庭成员Shirley。有没有办法做到这一点?输出文件将如下所示。

Kate Rhodes 
Shirley Rhodes 
+3

你的问题应该包括如何处理第三列中的多列逗号分隔值。另外,你在PerlMonks上的问题版本(顺便说一下,在多个论坛中同时提出同样的问题)在'Rhodes,Mich'有一个空间。您*必须*准确而准确地解释您的问题,否则您得到的答案将无法解决实际问题。 – Borodin 2012-04-27 22:48:50

回答

1

这里得到你想要输出的一种方式,因为你的输入...

use warnings; 
use strict; 

my %names; 
while (<DATA>) { 
    next if /^ID/; 
    my ($first, $last) = (split)[1 .. 2]; 
    $last =~ s/,//; 
    push @{ $names{$last} }, $first; 
} 
print "$_ Rhodes\n" for @{ $names{Rhodes} }; 

__DATA__ 
ID  NAME FAMILYTAG EFFECT 
001 John  Black    Positive 
002 Kate  Rhodes, Mich   Positive 
003 Aaron Sunders   Negative 
004 Shirley Rhodes   Negative 
005 Dexter Sunders  Positive 

Copied from my Answer on PerlMonks

+0

嗨的工具,我看到..也问过一个问题:)我想知道的是这只是匹配所有条目与Rhodes?剧本应该读在凯特,但我不知道这是否是它在做什么? – 2012-04-27 16:13:39

+0

@toolic:您明确知道内部知识数据*实际*在逗号后有空格! – Borodin 2012-04-27 22:44:45

0
#!/usr/bin/perl 

use strict; 
use warnings; 
my %db; 

open (F,'1.pl.tst'); 

my $find="Kate"; 
while(<F>) 
{ 
    chomp; 
    if (/^(\d+)[\t\ ]+(\w+)[\t\ ]+([^\t\ ]+)[\t\ ]+(\w+)$/) 
    { 
     $db{$1}{'name'}=$2; 
     $db{$1}{'family'}=[split(',',$3)]; 
     $db{$1}{'effect'}=$4; 
    } 
} 

my @[email protected]{name2family($find)}; 
foreach (@family) 
{ 
    family2name($_); 
} 

sub name2family 
{ 
    my $name=shift; 
    foreach (keys %db) 
    { 
     if ($db{$_}{'name'} eq $name) 
     { 
      return $db{$_}{'family'}; 
     } 
    } 
} 

sub family2name 
{ 
    my $family=shift; 
    foreach my $k (keys %db) 
    { 
     foreach (@{$db{$k}{'family'}}) 
     { 
      if ($_ eq $family) 
      { 
       print $db{$k}{'name'}."\t\t".$_."\n"; 
      } 
     } 
    } 
} 
+0

一些指针:你应该总是使用'​​使用警告',并检查'​​open'调用的返回值。 'split'的第一个参数是一个正则表达式,'/,/',而不是一个字符串'',''。您不需要在字符类括号'[\ t]'内部转义空格。 'chomp'是多余的,因为正则表达式中的'$'包含可能的尾随换行符。使用散列'%db'就像使用数组一样。 – TLP 2012-04-27 17:32:44

+0

使用警告给我错误,当使用“严格参考”时,不能使用字符串作为ARRAY参考。脚本运行良好,记住TLP的指针..但我没有得到任何输出。我试图输出它到一个txt文件,但它仍然是空白的。 – 2012-04-27 17:44:50

+0

使用制表符分隔文件的主要原因是这些字段本身可以包含空格。而不是'[\ t \]'你的正则表达式应该简单地使用'\ t'。更好的是,使用'split/\ t /'。 – Borodin 2012-04-27 22:32:06

1

我并不清楚是什么在FAMILYTAG的多个名称列表示,但我已经把它们放在一起,假设他们是替代姓氏。

use strict; 
use warnings; 

my %names; 
my %families; 

while (<DATA>) { 
    next unless /^\d/; 
    my ($id, $name, $familytag, $effect) = split /\t/; 
    for my $tag (split /,/, $familytag) { 
    push @{ $names{$name} }, $tag; 
    push @{ $families{$tag} }, $name; 
    } 
} 

while() { 

    print "\nName: "; 
    chomp (my $name = <>); 
    last unless $name =~ /\S/; 
    print "\n"; 

    if (my $tags = $names{$name}) { 
    for my $tag (@$tags) { 
     my $names = $families{$tag}; 
     next unless @$names > 1; 
     printf "%s %s\n", $_, $tag for @$names; 
    } 
    } 
    else { 
    warn qq(No name "$name" found); 
    } 
} 


__DATA__ 
ID NAME FAMILYTAG EFFECT 
001 John Black Positive 
002 Kate Rhodes,Mich Positive 
003 Aaron Sunders Negative 
004 Shirley Rhodes Negative 
005 Dexter Sunders,Hark Positive 

输出

E:\Perl\source>ff.pl 

Name: Kate 

Kate Rhodes 
Shirley Rhodes 

Name: Aaron 

Aaron Sunders 
Dexter Sunders 

Name: Mike 

No name "Mike" found at E:\Perl\source\ff.pl line 31, <> line 3. 

Name: Dexter 

Aaron Sunders 
Dexter Sunders 
+0

关于最近的一个问题,使用'while()'。 :) – TLP 2012-04-28 05:58:48

+0

@TLP:我在写'while(){...}','while while(1){...}'和'{... redo; }当我需要一个无限循环时。 – Borodin 2012-04-28 09:21:14

0

Text::CSV可以告知使用不同的分隔符;在这种情况下为"\t"

use Text::CSV; 

my $tsv = Text::CSV->new ({ sep_char => "\t" }); 

然后使用$tsv对象类似于$csv对象在该模块的例子。

相关问题