2011-12-28 2 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

Он совпадает с начала строки (^) до более :, захватив все, что между ними ((.*?)), и любыми следующими пространствами (\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 регулярное выражение, которое соответствует что-то в то время как $stringstring является замена в матче. Простым примером является:

$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 (Hash of Arrays).

Давайте приведем несколько примеров строк:

____________________________________________________ 
|  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

На самом деле нет ничего старого или неиспользованного использования '$ _' неявно, пока оно находится в небольшой области (две строки кажутся прекрасными). В этом случае это не так много. 'if' и неявные переменные являются частью языка; при их использовании они являются мощными и понятными; не записывайте их так быстро. Кроме того, используя 'split', как это, вы просто хотите проверить [' perldoc -f split'] (http://p3rl.org/split), чтобы узнать, что он делает! –

+0

p.s. не уменьшилось, время выглядит плохо, хотя –

+0

@JoelBerger - Вы правы, что предполагаемое использование '$ _' в этом конкретном случае не ухудшает читаемость, но оно действительно не улучшает его. Программирование - это 10% -ное кодирование и 90% обслуживание, а '$ _' просто делает эту 90% -ную часть сложнее, поэтому ее не поощряют. У вас нет полного контроля над '$ _', поэтому он может измениться без вашего ведома. Конвей не поощрял использование _post-fixed_ 'if' и использование' except' вместо 'if'. Тем не менее, он, вероятно, одобрил бы пост, зафиксированный «если» в этом конкретном случае. –

Смежные вопросы