Они используют много старых ярлыков, которые больше не используют большинство людей. Вот код снова с отсутствующей переменной по умолчанию. Я также перевернул оператор unless
в более стандартный формат. То есть я сделал это оператором if
и поместил next
как часть блока if
:
while ( $_ = <> ) {
if (not $_ =~ s/^(.*?):\s*//) {
next;
}
$HoA{$1} = [ split(/\s+/, $_) ];
}
Итак, мы устанавливаем значение $_
из оператора diamond . Это в основном берет имена файлов в командной строке и читает каждую строку в этих файлах. Если в командной строке нет файлов, она считывает из 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:
, поскольку это самая длинная строка, которая заканчивается двоеточием. Помещая ?
после *
, вы делаете регулярное выражение как non-жадный - то есть оно будет соответствовать наименьшему возможному выражению. Таким образом:
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, и ищет строки, содержащие двоеточие. Если строка не содержит двоеточия, она читает следующую строку.
Если строка содержит двоеточие, первая часть строки до first двоеточия и все последующие пробелы удаляются из строки.
$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:"] |
|_________________|________________________________|
Обратите внимание, что у последнего будет пробел в конце ключа. Это "Гхи", а не "Гхи".