在下面的Perl例如,正则表达式被使用,即,next unless s/^(.*?):\s*//;
但是,如何理解这种正则表达式,s/^(.*?):\s*//
S的正则表达式/ ^(*。): S * //
while (<>) {
next unless s/^(.*?):\s*//;
$HoA{$1} = [ split ];
}
在下面的Perl例如,正则表达式被使用,即,next unless s/^(.*?):\s*//;
但是,如何理解这种正则表达式,s/^(.*?):\s*//
S的正则表达式/ ^(*。): S * //
while (<>) {
next unless s/^(.*?):\s*//;
$HoA{$1} = [ split ];
}
它捕获(并存储为$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'
]
};
它从线(^
)的begining匹配,直到一个:
,捕捉无论是在((.*?)
)之间,以及任何后续空间(\s*
),并取代它(s/regex/replacement/
)与一个空字符串。
它返回一个真正的值(作出替换的数量),如果匹配,否则为false。
例如当$_
是foo: bar
,它将匹配foo:
和更换,从而导致$_
为bar
。之后,第一个捕获组$1
将包含foo
。
要了解更多看看:
他们使用了很多旧的快捷方式,大多数人不再使用的。这里是缺少默认变量的代码。我还将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+/, $_) ];
}
这是在命令行上列出的文件中读取,或从标准输入,并正在寻找包含冒号的行。如果该行不包含冒号,则会读取下一行。
如果一行包含冒号,则字符串的第一部分直到第一个冒号,并且任何后续的空白符将从该字符串中剥离。
$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”。
真的没有什么老旧或者没有用过隐式使用'$ _',只要它在一个小范围内(两行似乎很好)。在这种情况下,它可能没有多少意思。 '除非'和隐含变量是语言的一部分;如果使用得当,它们是强大而清晰的;不要这么快就写下来。进一步使用这样的'split'使得人们只想查看['perldoc -f split'](http://p3rl.org/split)来查看它的功能! – 2011-12-28 22:42:22
p.s.没有downvote,时间看起来不好 – 2011-12-28 22:51:50
@JoelBerger - 你说得对,在这种特殊情况下假设使用'$ _'不会影响可读性,但它并没有改善它。编程是10%的编码和90%的维护,'$ _'只是使这个90%的部分更难,这就是为什么它被阻止。你没有完全控制'$ _',所以它可以在你不知道的情况下改变。康威不鼓励使用_post-fixed_'if if,并且使用'unless'而不是'if'。但是,在这种特殊情况下,他可能会批准固定职位。 – 2011-12-29 15:36:09