如何在Perl中跳过非空格或数字的行?

时间:2009-04-04 04:15:31

标签: perl arrays string

我正在从像这样的文件中读取数据

while (<$fh>)
{
        @tmp = split; # <-- ?
        push @AoA, [@tmp];
}

我对此有几个问题。标记线有什么作用?它是否按行分割文件并将每行的元素存储到数组中?如果是这样,是否可以将@tmp转换为字符串或在@tmp上执行正则表达式?

基本上我想停止将数据推送到AoA上,如果我找到文件中的空格或整数以外的任何内容。我已经有了正则表达式:\ ^ [\ s \ d] * $ \

10 个答案:

答案 0 :(得分:8)

[@tmp = split;]是:

的简写
@tmp = split " ", $_, 0;

类似于

@tmp = split /\s+/, $_, 0;

但忽略任何前导空格,因此" foo bar baz"变为("foo", "bar", "baz")而不是("", "foo", "bar", "baz")

它使用文件处理程序$fh中的每一行并将其拆分,使用空格作为分隔符。

关于你想做什么,你为什么不在$_开始运行正则表达式?那是一个字符串。

你可以这样做:

while (<$fh>) {
    last unless  /^[\s\d]*$/; # break if a line containing something 
                              # other than whitespace or a number is found
    @tmp = split;
    push @AoA, [@tmp];
}

答案 1 :(得分:5)

当您想知道Perl内置的功能时,请阅读其文档。您获得的大部分答案仅仅是重述文档。使用任何语言的关键是学习如何使用其文档。如果您已阅读文档并且不理解,请在您的问题中提及:)

  • 您可以在perlfunc页面查看所有内置插件。

  • 在命令行中,您可以使用-f开关来perldoc仅提取内置文档:perldoc -f split

祝你好运,:))

答案 2 :(得分:3)

[@tmp = split;]在空白处拆分文件的每个传入行,并将这些单词作为数组存储在@tmp中。 (while()循环遍历文件中的每一行。)然后将包含@tmp的数组引用推送到@AoA。

实现'将@tmp转换为字符串'的最佳方法是,如果你想在那里做一些事情,就是永远不要将 out 转换为字符串; 拆分正在 $ _ 上运行,这是一个字符串(while循环隐式设置此项)。如果你在那个循环中执行像s / foo / bar /这样的正则表达式操作,它们将自动在$ _上运行。

所以,实现你想要的东西的一种方法(简化代码)是:

while(<$fh>) {
    last
        if /[^\s\d]/;
    push @AoA, [split];
}

如果您真的希望将@tmp重新转换为字符串,则可以执行以下操作:

my $tmp = join ' ', @tmp;

答案 3 :(得分:3)

while(<$fh>) {

这将逐行读取文件。文件的当前行存储在$_中。它与while($_ = <$fh>) {基本相同。从技术上讲,它扩展到while(defined($_ = <$fh>)) {,但它们非常接近同一个东西(无论哪种方式,它都是自动的,所以你不必担心它。)

  @tmp = split; 

split”没有参数(大部分)等同于“split /\s+/, $_”。它将当前行拆分为空格之间的项列表。因此,它将当前行拆分为单词列表(或多或少),并将此列表存储在数组中。但是,这条线很糟糕。 @tmp应符合my的要求。如果您在顶部有use strict;use warnings;,Perl会抓住这个。

  push @AoA, [@tmp];
}

这会将对包含@tmp中元素的匿名数组的引用推送到@AoA,这是一个数组数组(正如您可能已经知道的那样)。

所以最后,你有一个列表@AoA,其中列表中的每个元素对应于文件的一行,列表中的每个元素都是该行上单词的另一个列表。

简而言之,@tmp应使用my声明 ,您应该use strict;use warnings;。事实上,正如已经说过的那样,你可以完全取消@tmp

while(<$fh>) { push @AoA, [split] }

但是对于之后必须添加到此代码的任何人来说,使用临时数组可能会更好。

编辑:我错过了你想添加的正则表达式:

while(<$fh>) {
  last unless /^[\d\s]*$/;
  push @AoA, [split];
}

但是,/^[\d\s]*$/不会捕获所有整数 - 具体而言,它不会匹配-1。如果您希望它与负数匹配,请使用/^[\d\s-]*$/。此外,如果要匹配非整数(浮点数),可以使用/^[\d\s\.-]*$/,但我不知道您是否要匹配它们。但是,这些正则表达式将匹配1-35.5.5之类的无效条目,这些条目不是整数或数字。如果你想更加严格,试试这个:

LOOP: while(<$fh>) {
  my @tmp = split;
  for(@tmp) {
    # this line for floating points:
    last LOOP unless /^-?\d+(?:\.\d+|)$/;
    # this line for just integers:
    last LOOP unless /^-?\d+$/;
  }
  push @AoA, [@tmp];
}

答案 4 :(得分:2)

实际上,while (<$fh>)行按行分割文件;循环的每次迭代都会在$_中存储一个新行。

标记的行用空格分隔存储在$_中的行。因此,@tmp将是一个包含该行上所有字词的数组:如果该行包含foo bar baz,则@tmp将为('foo', 'bar', 'baz')

如果你想在相关的行上进行正则表达式匹配,那么你应该在分割线之前这样做。 perl中的正则表达式默认与$ _匹配,因此该行非常简单:

while (<$fh>)
{
    last unless /^[\s\d]*$/;
    @tmp = split;
    push @AoA, [@tmp];
}

答案 5 :(得分:1)

警告,\d并不表示Perl 5.8和5.10中的[0-9](除非您使用bytes编译指示)。它表示任何具有数字属性的UNICODE字符,例如MONGOLIAN DIGIT FIVE U + 1815(᠕),如果你想将它限制为只有空格和数字你可以用数学,你需要说{{ 1}}。

答案 6 :(得分:0)

第一行是一个像其他任何一个循环的循环,但它的“条件”从文件句柄$ fh读取一行输入到默认变量$ _。如果读取成功(即我们不在文件末尾),则执行正文。它基本上是“文件$ fh中的每一行”。

下一行是按空格(默认分隔符)拆分$ _中的项目(默认变量,请记住,因此它不会被分割调用),并将结果存储在@tmp中。最后一行将@tmp的REFERENCE添加到@AoA,这是一个数组引用数组。

所以,你想要做的就是说(在循环的顶部)

last if $_ =~ <apropriate regex here>;

答案 7 :(得分:0)

split获取它给出的字符串并通过拆分空格将其转换为数组 - 因为没有给出参数,它将拆分$_变量(这是从文件中给出的每一行依次在$fh

没有必要将@tmp转换为字符串,因为该字符串已经在$_变量中。

如果匹配任何不是空格或数字的单个字符,则为了停止循环:

last if /[\s\d]/;

这与您的版本略有不同,该版本将匹配仅包含非空格和/或非数字的任何完整行。

答案 8 :(得分:0)

好的很酷!

简写解释了很多。

所以我可以这样做..

while (<$fh>)
{
        if( /^[/s/d]*$/ ){
          //do something
        }else{
          //do something else;
        }

        @tmp = split;
        push @AoA, [@tmp];
}

答案 9 :(得分:0)

已经很好地涵盖了核心问题,但是有一个方面是“将@tmp转回一个字符串”子问题,这个问题尚未明确提及:

$_join ' ', @tmp 不等于$_将包含最初读取的行。 join ' ', @tmp将包含在该行上找到的单词,由单个空格连接。如果该行包含非空格空格(例如制表符),由多个空格分隔的单词或前导空格,则“完整”行的两个版本将不同。