繁体   English   中英

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

[英]How do I skip lines that aren't whitespace or a number in Perl?

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

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

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

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

[ @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];
}

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

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

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

祝好运, :)

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

最好的方式来完成“转换@tmp成一个字符串”,如果你想用它做什么就在那里,是从来没有转化出来的是一个字符串; split$ _上操作, $ _是一个字符串(while循环隐式设置了它)。 如果在该循环中执行s / foo / bar /等正则表达式操作,它们将自动在$ _上进行操作。

因此,一种实现您想要的内容的方法(稍微简化了代码)是:

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

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

my $tmp = join ' ', @tmp;
while(<$fh>) {

这将逐行读取文件。 文件的当前行存储在$_ 基本上与while($_ = <$fh>) { 从技术上讲,它可以扩展为while(defined($_ = <$fh>)) { ,但是它们与同一件事非常接近(并且无论哪种方式,它都是自动的,因此您不必为此担心)。

  @tmp = split; 

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

  push @AoA, [@tmp];
}

这会将对包含@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];
}

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

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

如果要在相关行上进行正则表达式匹配,则应在拆分行之前执行此操作。 perl中的正则表达式默认情况下与$ _匹配,因此该行非常简单:

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

警告,在Perl 5.8和5.10中\\d并不表示[0-9] (除非您使用bytes编译指示)。 这意味着任何具有digit属性的UNICODE字符,例如MONGOLIAN DIGIT FIVE U + 1815(᠕),如果要将其限制为仅空白和可以进行数学运算的数字,则需要说/^[\\s0-9]$/

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

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

因此,您想要做的就是说(在循环的顶部)

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

split接受给定的字符串,并通过在空白处进行拆分将其转换为数组-由于未提供任何参数,它将拆分$_变量(这将依次从$fh中的文件的每一行给出。

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

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

last if /[\s\d]/;

这与您的版本略有不同,您的版本将与仅由非空格和/或非数字组成的所有完整行匹配。

好的!

速记说明了很多。

所以我可以做到。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM