LXF70:Perl. Сортируем наш код
|
|
|
Часть 2. Напуганы непостижимыми операторами Perl и регулярными выражениями? Еще больше напуганы словом «непостижимые»? Марк Фиоретти (Marco Fioretti) может всё объяснить!
Содержание |
Перед тем, как отправиться в путешествие по королевству Perl, вы должны запомнить три типа переменных: скаляр, массив и хэш. Отмеченные символом $ скаляры содержат один кусочек информации, например строку. В нашем втором руководстве мы узнаем, как работать с более сложными величинами, массивами и хэшами, а затем покажем вам настоящую черную магию Perl — регулярные выражения.
Сортировка и перечисление
Вы помните, как массивы упорядочивают скаляры? Оператор списка Perl действует похожим образом. Это безымянная последовательность скаляров в круглых скобках. Хорошими вариантами использования оператора списка является присвоение значений двум или более переменным в одной инструкции или обмен значениями переменных тем или иным способом.
($X,$Y,$Z) = ($Y,$Z,$X); # Circular shift ($Name,$Surname,$Phone) = ('John', 'Smith',5556791); ($DARTH_VADER,@JEDI) = ('Anakin Skywalker', 'Yoda', 'Obi-Wan', 'Mace Windu');
Две первые строчки говорят сами за себя. В третьей строки список из левой части присваивания состоит из скаляра ($DARTH_VaDer) и именованного массива (@JEDI). Все знают, что случится после такого присвоения: на Тёмную Сторону Силы юный Энакин перейдёт в одиночестве. И поскольку вторым элементом списка является массив @JEDI, все остальные рыцари из правой части выражения попадут в него, в том же самом порядке.
Давайте теперь посмотрим на функцию splice(), которая используется для удаления, добавления или замены элементов массива. Для начала определим несколько планет:
@STAR_WARS_PLANETS = ('Naboo', 'Tatooine', 'Geonosis');
Используем splice() для того, чтобы добавить Coruscant и Alderaan сразу после Tatooine:
splice (@STAR_WARS_PLANETS, 2,0, ('Coruscant', 'Alderaan'));
Первым аргументом этой функции является имя массива, STAR_WARS_PLANETS. Затем идёт индекс элемента (считая с нуля!), с которого мы хотим начать склейку, в нашем случае это Tatooine. Третьим параметром является число элементов для удаления. Сейчас мы не хотим ничего удалять, нам надо только добавить несколько планет, поэтому в качестве третьего параметра передается «0». Последний, необязательный элемент — это список, который будет добавлен в позицию, номер которой вы только что указали. Если этот агрумента не указан, то splice() не добавит в массив ничего.
Если вы хотите упорядочить содержимое массива в алфавитном порядке, то вам понадобится функция sort(). По умолчанию она рассматривает содержимое переданного массива как строки, даже если там содержатся числа. Например, если вы введёте в командной строке следующее выражение:
perl -e "@A_LIST = ('Dominions', 180, 3, '10, Downing St.','Admiralty'); \ print join( \"\n\", sort @A_LIST), \"\n\";"
то получите отсортированный по алфавиту список:
10, Downing St. 180 3 Admiralty Dominions
Однако функция sort() может руководствоваться и другими критериями:
@SORTED_LIST = sort AS_I_WANT @UNORDERED_LIST;
AS_I_WANT — это функция, принимающая два скаляра в качестве аргументов и возвращающая −1, 0 или 1 в зависимости от того, какой параметр оказался меньше согласно вашему критерию. Мы рассмотрим такие функции в последующих выпусках.
Последнее замечание про массивы. Есть одна вещь, без которой не может жить ни один Perl-хакер, хотя она вовсе не выглядит как массив. Я говорю о нашем возлюбленном STDIN, стандартном потоке ввода любой «правильной» Unix-программы. К счастью, им очень просто пользоваться. Я упомянул здесь STDIN потому, что он может быть превращен в массив одним мановением руки:
@LINES = <STDIN>;
Вот так, одной единственной инструкцией вы внесли каждую строчку ввода в отдельный элемент массива @LINES. Удобно, не правда ли?
Чистый хэш
В первой части нашего руководства я вам рассказывал про хэши и их концепцию индексирования доступа к одним скалярам другими скалярами (ключами). Как вы знаете, хэш состоит из ключей, связанных со своими значениями. Если у вас есть хэш, гораздо проще работать с ним с помощью ключей, а не их значений. В конце концов, если бы вы просто хотели собрать все эти значения вместе в определённом порядке, вы бы взяли обычный массив, не правда ли?
В отличие от массивов, хэши в Perl никак не отсортированы — ни в порядке возрастания ключей, ни в порядке добавления элементов. Это значит, что к элементу хэша нельзя обращаться по его порядковому номеру, можно только по ключу. Это верно, даже если вы собрались удалить какой-то элемент хэша и его ключ. Для этого существует функция delete(), которая принимает в качестве параметра ключ элемента, подлежащего забвению. Пользоваться этой функцией необходимо, так как если вы, например, просто присвоите пустое значение соответствующему элементу хэша, то он не будет удалён, хотя значение этого элемента и станет равным null.
Первой вещью, которую приходится делать с элементом хэша, является выяснение того, присутствует ли он в хэше, и соответствует ли его ключу какое-нибудь значение. Для этих целей в Perl существуют две функции, названные (вы уже догадались?) exists() и define(). Используют их следующим образом:
if exists ($STAR_WARS_ACTORS{'Leia'}) { # do something...}; if defined ($STAR_WARS_ACTORS{'Leia'}) { # do something else...};
Первая команда выполнится, только если в хэше есть ключ 'Leia' вне зависимости от того, какое значение присвоено этому ключу. Второе выражение идёт еще дальше, оно истинно только в том случае, если в хэше есть ключ 'Leia' и если ему явно было присвоено какое-то значение.
Регулярные выражения
...
Подсказка
Подсчёт числа элементов массива
Как можно узнать, сколько элементов содержится в массиве или хэше? Очень просто, присвоить их скалярной переменной! Поскольку она может содержать только одно число, Perl поместит туда число элементов массива. Тот же способ работает с хэшами. Функция keys возвращает массив, содержащий только ключи хэша, так что его размер можно узнать следующим образом:
$HOW_MANY_JEDI = @JEDI; $HOW_MANY_ITEMS_INTO_AN_HASH = keys %SOME_HASH;
Как разрушить свою жизнь регулярными выражениями
Perl, вероятно, содержит гораздо больше регулярных выражений, чем все другие языки программирования. Для того, чтобы своими глазами увидеть, насколько мощными и неудобными они могут быть, посмотрите на самое длинное из всех, что я видел — http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html. Говорят, что оно проверяет правильность адреса e-mail, но я не могу это проверить. Если хотите научиться создавать такие же, прочитайте книгу Джефри Фридла «Регулярные выражения» (Jeffrey Friedl, «Mastering Regular expressions», O’Reilly, 2002).
Регулярные выражения: шпаргалка
Здесь приведён список основных метасимволов, используемых в регулярных выражениях Perl. Скопируйте его и держите поближе к клавиатуре, он действительно помогает сэкономить время.
- . — Любой символ за исключением перевода строки
- ^ — Начало строки
- $ — Конец строки
- * — Ноль или более предыдущих символов
- + — Один или более предыдущий символ
- ? — Ноль или один предыдущий символ
- \n — Перевод строки
- \t — Табуляция
- \w — Числа и алфавитные символы, вне зависимости от регистра
- \W — Все символы, кроме букв или цифр
- \d — Старые добрые цифры: 0, 1 и так до 9.
- \D — Всё, кроме цифр.
- \s — Пробельные символы: пробел, табуляция, перевод строки.
- \S — Любой не пробельный символ.
- \b — Граница слова.
- | — Выбор из двух вариантов (например A|B).
- [] — Квадратные скобки определяют диапазон символов.
- () — Круглые скобки сохраняют соответствующую им подстроку.
Примечания: Когда вам необходимо вставить в регулярное выражение один из этих символов в его буквальном смысле, например знак «+», нужно поставить перед ним обратную косую черту (\).
A+ # Одна или несколько букв A \+ # один знак "+" \++ # Один или несколько знаков "+"