Изучаем Perl


Глава 7 "Регулярные выражения"



Глава 7 "Регулярные выражения"

1. Вот несколько возможных ответов:

а) /а+ь*/

б) /\\*\**/ (Вспомним, что обратная косая черта отменяет значение следующего за ней специального символа.)

в) / ($whatever) {3} / (Не забудьте про круглые скобки, иначе множитель будет действовать только на последний символ $whatever; этот вариант не проходит также в том случае, если $whatever содержит специальные символы.)

г) /[\000-\377] (5}/ или /(. |\п) (5)/ (Использовать точку без дополнительных знаков здесь нельзя, потому что она не соответствует символу новой строки.)

д) / (л l \s) (\s+) (\s+\2)+ (\s | $) / (\s — это не пробельный символ, а \2 — ссылка на все, что есть "слово"; знак " или альтернативный пробельный символ гарантирует, что \s+ начинается на границе пробельного символа.)

2. а) Вот один из способов решения этой задачи:

while (<STDIN>) {

if (/a/i && /e/i &S /i/i &S /o/i && /u/i) ( print;

)

Здесь у нас приведено выражение, состоящее из пяти операций сопоставления. Все эти операции проверяют содержимое переменной $_, куда управляющее выражение цикла while помещает каждую строку. Выражение даст значение "истина" лишь в том случае, если будут найдены все пять гласных.

Обратите внимание: если любая из пяти гласных не обнаруживается, остальная часть выражения пропускается, потому что операция && не вычисляет свой правый аргумент, если значение левого аргумента — "ложь".

б) Еще один способ:

while (<STDIN>) (

if (/a.*e.*i.*o.*u/i) ( print;

} )

Этот ответ, как оказывается, проще. Здесь у нас в операторе if используется более простое регулярное выражение, которое ищет пять гласных в указанной последовательности, разделенных любым количеством символов.

в) Вот один из способов решения этой задачи:

while “STDIN” (

if (/"[eiou]*a[лiou]*e[лaou]*i[^aeu]*o[лaei]*u["aeio]*$/i) ( print;

> )

Выглядит уродливо, но работает. Чтобы написать такое, просто подумайте: "Что может стоять между началом строки и первой буквой а?", а затем "Что может стоять между первой буквой а и первой буквой е?". В конце концов все решится само, от вас потребуется минимум усилий.

3. Вот один из способов решения этой задачи:

while (<STDIN>) {

chomp;

($user, $gcos) = (split /:/)[0,4];

($real) = split (/,/, $gcos) ;

print "$user is $real\n";

}

Во внешнем цикле while производится считывание по одной строке из файла паролей в переменную $_. По достижении последней строки цикл завершается.

Вторая строка тела цикла while означает разбиение строки на отдельные переменные с использованием в качестве разделителя двоеточия. Два из этих семи значений заносятся в отдельные скалярные переменные с имеющими смысл (мы надеемся) именами.

Поле GCOS (пятое поле) затем разбивается на части с использованием в качестве разделителя символа запятой, и список-результат присваивается одной скалярной переменной, заключенной в круглые скобки. Эти скобки играют важную роль — они указывают, что операция присваивания должна быть не скалярной, а для массива. Скалярная переменная $геа1 получает первый элемент списка-результата, а остальные элементы отбрасываются.

Оператор print затем выводит результаты на экран.

4. Вот один из способов решения этой задачи:

while (<STDIM>) (

chomp;

($gcos) = (split /:/)[4];

($real) =split(/,/, $gcos);

($first) ° split(/\s+/, $real);

$seen($first>++;

} foreach (keys %seen) (

if ($seen($_) > 1) {

print "$_ was seen $seen($_) times\n";

) }

Цикл while работает во многом так же, как цикл while из предыдущего упражнения. Помимо разбивки строки на поля и поля GCOS на реальное имя (и другие компоненты), в этом цикле осуществляется также разбиение реального имени на собственно имя и остальную часть. После определения имени элемент хеша в %seen инкрементируется, отмечая тот факт, что мы нашли конкретное имя. Обратите внимание: оператор print в этом цикле не используется.

В цикле foreach осуществляется проход по всем ключам хеша %seen (именам из файла паролей) с присваиванием каждого из них по очереди переменной $_. Если значение, записанное в %seen по данному ключу, больше 1, значит, это имя уже встречалось. Оператор if проверяет, так ли это, и при необходимости выводит соответствующее сообщение.

5. Вот один из способов решения этой задачи:

while (<STDIN>) (

chomp;

($user, $gcos) = (split /:/)[0,4];

($real) = split /,/, $gcos;

($first) = split (/\s+/, $real);

$seen($first) .= " $user";

}

foreach (keys %names) (

$this == $names{$_);

if ($this =~ /. /) {

print "$_ is used by:?this\n";

} }

Эта программа похожа на ответ к предыдущему упражнению, но вместо того чтобы просто подсчитывать, сколько раз у нас встречалось определенное имя, мы присоединяем регистрационное имя пользователя к элементу хеша % names, указывая имя в качестве ключа. Так, для Фреда Роджерса (регистрационное имя mrrogers) $names {"Fred"} становится равным " mrrogers", а когда появляется Фред Флинтстоун (регистрационное имя fred), $names ( "Fred" } становится равным " mrrogers fred". После завершения цикла у нас имеется список имен и список регистрационных имен всех имеющих данное имя пользователей.

В цикле foreach, как и в ответе к предыдущему упражнению, осуществляется проход по полученному в результате хешу, но вместо того, чтобы проверять, больше ли единицы значение элемента хеша, мы должны проверить, есть ли в этом значении более одного регистрационного имени. Для этого нужно занести значение в скалярную переменную $this и посмотреть, есть ли в нем после какого-нибудь символа пробел. Если есть, то одному реальному имени соответствуют несколько регистрационных имен, которые и указываются в выдаваемом в результате сообщении.









Начало  Назад  Вперед


Книжный магазин