2011-12-28 196 views

回答

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

它从线(^)的begining匹配,直到一个:,捕捉无论是在((.*?))之间,以及任何后续空间(\s*),并取代它(s/regex/replacement/ )与一个空字符串。

它返回一个真正的值(作出替换的数量),如果匹配,否则为false。

例如当$_foo: bar,它将匹配foo:和更换,从而导致$_bar。之后,第一个捕获组$1将包含foo

要了解更多看看:

-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+/, $_) ]; 
} 

这是在命令行上列出的文件中读取,或从标准输入,并正在寻找包含冒号的行。如果该行不包含冒号,则会读取下一行。

如果一行包含冒号,则字符串的第一部分直到第一个冒号,并且任何后续的空白符将从该字符串中剥离。

$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”。

+1

真的没有什么老旧或者没有用过隐式使用'$ _',只要它在一个小范围内(两行似乎很好)。在这种情况下,它可能没有多少意思。 '除非'和隐含变量是语言的一部分;如果使用得当,它们是强大而清晰的;不要这么快就写下来。进一步使用这样的'split'使得人们只想查看['perldoc -f split'](http://p3rl.org/split)来查看它的功能! – 2011-12-28 22:42:22

+0

p.s.没有downvote,时间看起来不好 – 2011-12-28 22:51:50

+0

@JoelBerger - 你说得对,在这种特殊情况下假设使用'$ _'不会影响可读性,但它并没有改善它。编程是10%的编码和90%的维护,'$ _'只是使这个90%的部分更难,这就是为什么它被阻止。你没有完全控制'$ _',所以它可以在你不知道的情况下改变。康威不鼓励使用_post-fixed_'if if,并且使用'unless'而不是'if'。但是,在这种特殊情况下,他可能会批准固定职位。 – 2011-12-29 15:36:09