[英]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-3
和5.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];
}
第一行是一个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.