我正在从像这样的文件中读取数据
while (<$fh>)
{
@tmp = split; # <-- ?
push @AoA, [@tmp];
}
我对此有几个问题。标记线有什么作用?它是否按行分割文件并将每行的元素存储到数组中?如果是这样,是否可以将@tmp转换为字符串或在@tmp上执行正则表达式?
基本上我想停止将数据推送到AoA上,如果我找到文件中的空格或整数以外的任何内容。我已经有了正则表达式:\ ^ [\ s \ d] * $ \
答案 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-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];
}
答案 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
将包含在该行上找到的单词,由单个空格连接。如果该行包含非空格空格(例如制表符),由多个空格分隔的单词或前导空格,则“完整”行的两个版本将不同。