在下面的Perl示例中,使用了正则表达式,即next unless s/^(.*?):\s*//;
但是,如何理解这个正则表达式s/^(.*?):\s*//
while ( <> ) {
next unless s/^(.*?):\s*//;
$HoA{$1} = [ split ];
}
答案 0 :(得分:4)
它捕获(并存储为$1
)一些文本,直到:
。然后它删除捕获的文本,分号和任何尾随空格。
超出正则表达式:如果正则表达式成功完成其工作,则代码将捕获的文本用作散列键,其值为数组引用。该数组的元素是在空格上拆分的其余行。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my %HoA;
while ( <DATA> ) {
#next unless s/^(.*?):\s*//;
next unless
s/ #s is replace match operation
^ #start at the beginning of the line
( #begin capture $1
.*? #capture anything, but not greedy, i.e. stop before :
) #end capture $1
: #literal colon (must match)
\s* #optional whitespace
//x; #replace match with nothing, x flag allows formatting and comments
$HoA{$1} = [ split ];
}
print Dumper(\%HoA), "\n";
__DATA__
Thingy: Thing1 Thing2
Stuff: mystuff yourstuff
other line that doesn't have a colon
给出
$VAR1 = {
'Thingy' => [
'Thing1',
'Thing2'
],
'Stuff' => [
'mystuff',
'yourstuff'
]
};
答案 1 :(得分:1)
它从行(^
)的开头到:
匹配,捕获其间的任何内容((.*?)
)和任何后续空格(\s*
),以及用空字符串替换它(s/regex/replacement/
)。
如果匹配则返回true值(替换次数),否则返回false。
例如,当$_
为foo: bar
时,它将与foo:
匹配并被替换,从而导致$_
为bar
。在此之后,第一个捕获组$1
将包含foo
。
要了解更多信息,请查看:
答案 2 :(得分:-1)
他们使用了大多数人不再使用的旧快捷方式。这是使用缺少的默认变量的代码。我还将unless
语句转换为更标准的格式。也就是说,我将其设为if
语句,并将next
作为if
块的一部分:
while ( $_ = <> ) {
if (not $_ =~ s/^(.*?):\s*//) {
next;
}
$HoA{$1} = [ split(/\s+/, $_) ];
}
因此,我们从diamond operator设置$_
的值。这基本上采用命令行上的文件名称并读取这些文件中的每一行。如果命令行中没有文件,则从STDIN读取。
正则表达式比较棘手。 ^
将正则表达式锚定到行的开头。否则,正则表达式可以出现在该行的任何位置。例如:
/FOO/ #Will match "FOOBAR" "BARFOOBAR", or "BARFOO"
/^FOO/ #Will only match "FOOBAR" and not "BARFOOBAR" or "BARFOO"
.
表示任何角色。 *
表示前面的零个或多个。因此,.*
表示任意数量的字符(包括零个字符。例如:
/^.*:/ #Will match any combination of characters followed by a colon (:).
因此,这将匹配一行中的:
(零或更多),或this is a test:
棘手的部分是?
,它以非常微妙的方式改变了*
的含义。通常,正则表达式是贪婪的。他们试图匹配最大的匹配,所以如果你有一个字符串:
my $string = "abc:def:ghij";
$string =~ /^.*:/;
正则表达式将匹配最大的东西。因此,上面的内容将匹配abc:def:
,因为它是以冒号结尾的最长字符串。通过将?
放在*
之后,将正则表达式设为非贪婪 - 即它将匹配最小的可能表达式。因此:
my $string = "abc:def:ghij";
$string =~ /^(.*):/ #Matches "abc:def:
$string =~ /^(.*?):/ #Matches "abc:"
\s
表示任何空格,通常表示空格或制表符。 *
表示零个或多个空格。因此,这可能不是空格或多个空格。
my $string = "abc:def: foo";
$string =~ /^(.*?):\s*/; #Matches "abc:"
$string = "abc: This is a test";
$string =~ /^(.*?):\s*/; #Matches "abc: "
现在,正则表达式前面的s
表示替换。基本格式为:
$string =~ s/regex/string/;
其中regex
是与$string
中的内容匹配的正则表达式,而string
是匹配的替代。一个简单的例子是:
$string = "My name is David";
$string =~ s/David/Bill/; #String is now "My name is Bill"
在这种情况下,正则表达式匹配的字符只是替换为空。也就是说,它们会从字符串中删除:
$string = "abc: def";
$string =~ /^(.*?):\s*/; #$string is now "def". "abc: " has been removed
所以,再看一下你的代码:
while ( $_ = <> ) {
if (not $_ =~ s/^(.*?):\s*//) {
next;
}
$HoA{$1} = [ split(/\s+/, $_) ];
}
这是从命令行或STDIN上列出的文件中读取,并且正在查找包含冒号的行。如果该行不包含冒号,则会读取下一行。
如果一行包含冒号,则从字符串中删除字符串的第一部分,直到第一个冒号和任何后面的空格。
$1
指的是在前一个正则表达式的括号内匹配的字符串部分。这是第一个冒号的字符串的第一部分。 split
正在拆分由空格分隔的字符串的剩余部分,并使其成为所谓的匿名列表。也就是说,这是创建数组的哈希(这就是为什么这个哈希被称为 HoA (数组的哈希)。
让我们举几个字符串示例:
____________________________________________________
| STRING | RESULTS |
|_________________|________________________________|
| abc: foobar | $HoA{abc} = ["foobar"] |
| def:bar fu | $HoA{def} = ["bar", "fu"] |
| ghi:jkl:mno | $HoA{ghi} = ["jkl:mno"] |
| ghi : jkl: mn: | $HoA{"ghi "} = ["jkl:", "mn:"] |
|_________________|________________________________|
请注意,最后一个将在键的末尾有一个空格。它是“ghi”而不是“ghi”。