s / ^(。*?)的正则表达式:\ s * //

时间:2011-12-28 20:30:43

标签: regex perl

在下面的Perl示例中,使用了正则表达式,即next unless s/^(.*?):\s*//;但是,如何理解这个正则表达式s/^(.*?):\s*//

while ( <> ) {
next unless s/^(.*?):\s*//;
$HoA{$1} = [ split ];
}

3 个答案:

答案 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”。