将文件中的行拆分为多个部分

时间:2014-02-25 16:53:08

标签: string perl file split lines

希望这是寻求帮助的正确方法。我已经设置了一个分为三个部分的作业,第一部分我遇到了麻烦。我必须将文件加载到我已经完成的List中,它是我需要将文件的每一行拆分为3的部分 目前我的编程看起来像:

use warnings;
use strict;

sub LocationCount ($$$$) {
  my ($FileName, $DKm, $Lat, $Lon) = @_;
  my ($Index, $Species, $Latitude, $Longitude);
  my @List;

  open(INF, "<", $FileName) or die("Cannot open Mammal.txt\n");
  @List = <INF>;
  @List = split("\t", @List);

  for ($Index = 0 ; $Index < @List ; $Index++) {
    print("Species Name: $List[0]\n");
    print("Latitude: $List[1]\n");
    print("Longitude: $List[2]\n");
  }
}

运行完整程序时返回的是:

Use of uninitialized value $List[1] in concatenation (.) or string at Assignment.pl line 19, <INF> line 125000.
Use of uninitialized value $List[2] in concatenation (.) or string at Assignment.pl line 20, <INF> line 125000.
Species Name: 125000
Latitude:
Longitude:

基本上应该是这样的:

Species Name: Myotis nattereri
Latitude: 54.07663633
Longitude: -1.006446707

Species Name: Pipistrellus pipistrellus sensu lato
Latitude: 56.12259134
Longitude: -4.49369336

(x125,000)

给我的txt文件是这样排序的,物种名称后跟纬度标签,然后是经度标签:

Myotis nattereri 54.07663633 -1.006446707 
Pipistrellus pipistrellus sensu lato 56.12259134 -4.49369336 
Myotis daubentonii 52.24773003 -1.084432324

每个物种都在自己的路线上

我问的基本上是,为什么它会返回文件中的行数而不是将每行分成三部分?在摆弄它的同时,我设法让它重复:

Species Name: Myotis nattereri
Latitude: 54.07663633
Longitude: -1.006446707

125,000次,这不是我想要发生的事情。 感谢您的帮助,如果我说错了或格式错误,我真的很抱歉。我已经找到了其他答案,并尝试了一些有类似问题的人的答案,但他们只是不适合我。

4 个答案:

答案 0 :(得分:2)

通过更改:

逐行处理
@List = <INF>;
@List = split ("\t", @List);

while (<INF>) {
    chomp;
    my ($species, $latitude, $longitude) = split "\t";
    ....

答案 1 :(得分:1)

问题在于

@List = split("\t", @List);

split运算符需要一个字符串作为其第二个参数,并对其应用标量上下文。在此处传递数组将导致尝试拆分包含数组中元素数的字符串。

例如

perl -E "@data = qw/ a b c d /; say for split /\t/, @data"

产生

4

还有许多其他问题

  • 绝不能在Perl中使用子例程原型(如sub LocationCount ($$$$))。它们与其他语言的原型非常不同,并且不按照您的想法行事

  • Perl不会强制执行它,但熟悉该语言的程序员会感谢您使用小写字母和下划线表示本地标识符。大写字母保留用于全局名称,例如包名称

  • 您应该使用词汇文件句柄而不是全局词句($inf而不是INF)。选择open

  • 的三参数形式做得好
  • split的第一个参数是正则表达式。如果传递一个简单的字符串,那么它仍然会被编译为正则表达式,因此最好使用斜杠作为分隔符,如split /\t/, $line

  • Perl比C风格的for列表有更好的选择。如果您对数组中的索引不感兴趣,那么您只需编写for (@array) { ... }

您的代码看起来应该是这样的

use warnings;
use strict;

sub location_count {

  my ($filename, $dkm, $lat, $long) = @_;

  open my $inf, '<', $filename or die qq{Unable to open "$filename" for input: $!};
  my @list = <$inf>;

  for my $line (@list) {
    my @fields = split /\t/, $line;
    printf "Species Name: %s\n", $fields[0];
    printf "Latitude:     %s\n", $fields[1];
    printf "Longitude:    %s\n", $fields[2];
  }
}

答案 2 :(得分:0)

在顶部声明:

use diagnostics;

当您第一次学习Perl的警告时,我更喜欢diagnostics有用的工具。

您需要从该行中删除换行符。当您使用chomp数组时,它将从数组中每个元素的末尾删除换行符。

open(INF,"<",$FileName) or die ("Cannot open Mammal.txt\n");
@List = <INF>;
chomp(@List);         ### Add this before spliting
@List = split ("\t", @List);

再次运行脚本。

另外,如果您确定自己正在做什么,那么您可以使用 在顶部no warnings 'uninitialized';,看看输出是什么。

答案 3 :(得分:0)

要处理infile,请使用

while (my $line = <INF>)
{
    chomp $line;
    my @List = split /\t/, $line;

    print("Species Name: $List[0]\n");
    print("Latitude: $List[1]\n");
    print("Longitude: $List[2]\n\n"); 
}

而不是

@List = <INF>;
@List = split ("\t", @List);

for($Index=0;$Index<@List;$Index++)
{
    print("Species Name: $List[0]\n");
    print("Latitude: $List[1]\n");
    print("Longitude: $List[2]\n"); 
}