1 \section{Регулярные выражения
}
4 У меня была проблема, я решил для ее решения использовать регулярные
5 выражения. Теперь у меня две проблемы.
8 \subsection{Великий и могучий UTF8
}
10 Для начала --- немножечко истории. Ведь у того, кто не знает прошлого, нет
11 будущего! Дело в том, что испокон веков символы было принято кодировать
12 одним байтом. А одним байтом можно закодировать
256 символов (от
0 до
255). Вот
13 почему, вы думаете, во многих самоучителях по программированию
14 предпочитают использовать только латинские буквы? Даже в русских
15 учебниках часто можно увидеть транслит вместо родной кириллицы. А дело в
16 том, что первые
128 кодов таблицы символов (от
0 до
127) --- это символы
17 \textbf{ASCII
} (
\textbf{A
}merican
\textbf{S
}tandard
\textbf{C
}ode for
18 \textbf{I
}nformation
\textbf{I
}nterchange). Проблем с ними
19 никогда не бывает, во всех кодировках первые
128 кодов одни и те же. Никто не
20 хочет мучиться с национальными алфавитами, коим отведены остальные
128
21 кодов. И, собственно, отлично! Один символ = один байт, удобно и просто. Но
22 из-за всяких унтерменшей и просто идиотов, которые думали, что они самые
23 умные, появилась тьма различных кодировок! Одних только русских я помню
24 как минимум три. Началась неразбериха, холиворы и вообще полный Ад и
25 Израиль. До сих пор многие чувствуют дискомфорт в нижней части тела,
26 получив иероглифы по электронной почте или, например, увидев кракозябры
27 на русскоязычных сайтах. Не знаю, как сейчас, но раньше пользователи ICQ
28 часто страдали, посылая друг другу иероглифы. Так и жили люди, тысячи
29 тысяч языков и у каждого по
2-
3 кодировки. Просто ужас!
31 Мир нужно было спасать и храбрые программисты придумали utf8. Теперь
32 совершенно не обязательно, что один символ занимает только один байт.
33 Символ может обозначаться и двумя, и даже четырьмя байтами! Непосвященный
34 не поймет суровости этого решения, но, когда я узнал, что, кодя на Си,
35 больше не могу обрабатывать символ за символом, просто сдвигаясь на один
36 байт — мой мир рухнул. Но речь не обо мне и вообще мы не Си учим.
38 Всё прогрессивное человечество переходит на UTF-
8, ведь четырёх байт хватит
39 на всех! Но и здесь первые
128 бит --- это символы ASCII, а дальше идут
40 национальные и другие смешные символы. Юникод широкими шагами шагает по
41 планете. Jabber (он же XMPP) уже кодирует все сообщения в UTF-
8 и никаких проблем с
42 кодировкой! Перл тоже не отстает. Поэтому отныне и навсегда в своих
43 скриптах, работая с русским, мы будем использовать utf-
8. Где бы вы не кодили,
44 что бы вы не делали, скрипт --- это храм utf-
8, плевать что вовне. Хотя, если вы
45 работаете только с ASCII символами, совершенно не имеет значения, какую
46 кодировку вы используете.
48 Пользователи Linux давно локализуют свои машины под utf-
8, а форточники с
49 упорством упоротых продолжают безумствовать! Судите сами, консоль у них
50 работает в кодировке cp866, а кодировка по умолчанию для граф. среды — cp1251.
51 Жесть! Но если эти два обстоятельства пользователи ШИНДОУС будут
52 постоянно держать в голове — всё будет хорошо. Любой входящий текст мы
53 будем преобразовывать в utf-
8, обрабатывать его в недрах Perl,
54 преобразовывать обратно и посылать куда следует. Такие дела.
56 Этот листинг рассчитан на пользователей windows, но будет интересен и
61 Директива из первой строки говорит, что наш скрипт набран и работает в utf-
8.
62 Не забудьте выбрать utf-
8 в вашем текстовом редакторе, когда будете
63 набирать листинг! Модуль
\remph{Encode
} из второй строки необходим для
64 перекодирования текста из одной кодировки в другую. Далее нужно сказать,
65 чтоб текст со стандартного ввода/вывода перекодировался из cp866 в utf-
8, это
66 можно сделать одной командой, которая закоментирована в строке
6 или
67 двумя из строк
7 и
8. Я выбрал второй вариант, так как он более наглядный.
68 Теперь перл будет автоматически перекодировать входящий текст с STDIN из
69 cp866 в utf-
8 и кодировать выводимый на STDOUT текст из utf-
8 в cp866.
71 Пользователи Windows должны внимательно прочитать эту главу, ибо я верстаю
72 на linux и возлагаю миссию выставления правильной кодировки, в случае
73 работы с кириллицей, на них.
75 \subsection{Поиск по шаблону
}
77 Регулярные выражения --- это невероятно мощная вещь! Перл славится своей
78 способностью обрабатывать текст, и по большей части он обязан этим
79 именно регулярным выражениям. С другой стороны регэкспы также славятся
80 своей сложностью. О регулярках пишут целые книги. Что же такое
81 регулярные выражения? Вики гласит:
83 \remph{Регулярные выражения (англ. regular expressions, сокр. RegExp, RegEx,
84 жарг. регэкспы или регексы) — это формальный язык поиска и осуществления
85 манипуляций с подстроками в тексте, основанный на использовании
86 метасимволов (символов-джокеров, англ. wildcard characters). По сути,
87 это строка-образец (англ. pattern, по-русски её часто называют
88 «шаблоном», «маской»), состоящая из символов и метасимволов и задающая
91 В основном регулярные выражения служат двум целям — поиску и замене текста.
92 Но регулярные выражения гораздо гибче, чем, например, поиск и замена в
93 \emph{notepad.exe
}~. Как и сказано в вике, мы можем описать искомый
94 текст в общих чертах с помощью метасимволов. Например, на языке регулярных
95 выражений можно попросить Perl найти все слова, начинающиеся
96 с большой буквы, или найти все числа в тексте. Рассмотрим простейший
97 случай регулярных выражений:
101 В строке
6 с помощью оператора привязки
\remph{=\~
} мы говорим интерпретатору,
102 что искать подстроку нужно в скаляре \$text. Без этого оператора поиск
103 осуществлялся бы в скаляре по умолчанию. Два слэша окружают наше
104 регулярное выражение. Конструкция:
109 Вернёт истину, если в скаляре содержится искомая подстрока. Но мы по
110 прежнему недалеко ушли от блокнота. Давайте представим, что что-то
111 случилось с телефоном и некоторые буквы было слышно плохо:
115 Благодаря ключу i, который заставляет игнорировать регистр символов в
116 регулярном выражении, мы всё-равно смогли ответить на звонок. Но и это не
117 всё. Давайте сделаем наш скрипт более универсальным:
121 Так-то лучше. В этом листинге мы впервые использовали метасимволы и
122 сохранили в укромном месте кусочек найденной строки. Помните
123 интерполяцию специальных символов в двойных кавычках? Например, символа
124 перевода строки. Так вот, дела с метасимволами в регулярных выражениях
125 обстоят похожим образом.
\textbackslash w например соответствует любой букве или
126 символу подчеркивания. Звездочка и плюс — квантификаторы. Они говорят,
127 сколько раз может повториться символ, стоящий слева. Звёздочка
128 соответствует нулю или бесконечному количеству, а плюс --- одному или
129 бесконечности. Скобки тоже имеют особый смысл. Заключенное в них
130 выражение будет сохранено в специальный скаляр \$
1; если б скобок было две,
131 то содержимое вторых скобок было бы сохранено в скаляр \$
2 и так далее.
132 Сохраненный кусочек текста мы используем для хранения имени, и выводим
133 его на экран всё там же, в строке
7.
135 На всякий случай, я расшифрую регулярное выражение. Строка начинается с
136 буквы или знака подчеркивания, которых может быть от нуля до
137 бесконечности штук. Затем идёт запятая и пробел. Следующий фрагмент
138 необходимо сохранить в спец. скаляр \$
1, если найдется текст
139 соответствующий этому выражению. Итак, в скобки у нас заключена по
140 крайней мере одна буква или символ подчеркивания.
142 Существует и другой, более громоздкий, но и более наглядный способ
143 сохранения фрагментов найденного текста:
150 Синтаксис таков: (?<имя>то_что_нужно_схоронить)
153 В нашем примере, фрагмент текста сохраняется в специальный хэш
\remph{\%+
},
154 получить его можно будет по ключу
\remph{name
} , что и происходит в строке
7.
156 %огромный листинг с побитой строкой
159 В строке
6 можно увидеть новый метасимвол
\emph{\textbackslash b
} , он
160 означает границу слова. Чтоб было понятней, приведу пример:
163 \bТы
\b \bустал
\b \bнаверно
\b?
\bХочешь
\b \bя
\b \bтебе
\b \bпесню
\b \bспою
\b?
166 Я явно обозначил границы слов для тебя. Достаточно забавный символ, т.к.
167 на самом деле граница слова --- вещь мнимая.
169 Создатель Perl сказал, что лень --- одна из главных добродетелей
170 программиста, поэтому я и стараюсь избегать лишней работы. В строке
6
171 есть новый квантификатор. В фигурных скобках указывается верхняя и
172 нижняя границы. Второй параметр опущен, поэтому считается, что данное
173 регулярное выражение найдет все слова длиной от пяти букв.
175 В выражении также использован ключ
\remph{g
} . Он говорит регулярному
176 выражению искать
\emph{глобально
}, во всей строке. Без этого ключа поиск
177 прекратился бы на первом найденном элементе.
179 \subsubsection{Жадность
}
181 Многие квантификаторы (такие, как плюс и звездочка) по умолчанию являются
182 жадными и пытаются захватить как можно больше символов:
186 Точка означает любой символ, кроме символа перевода строки. Многие
187 забывают про это. Наше выражение съест все символы вплоть до последнего
188 перевода строки, который находится между буквой
\remph{s
} и первой точкой
189 многоточия. Но лекарство от жадности существует!
195 Вопросик приглядит за звёздочкой и не даст ей хапануть лишнего.
196 Запусти этот скрипт и удивись :)
198 К сожалению, теперь наше регулярное выражение, напротив, слишком
199 лениво. Минимальный план для звёздочки --- это ноль символов, поэтому
200 выражение вообще ничего не захватит, гораздо логичней было бы заменить
201 звёздочку на плюс и тогда мы получим то, что хотели.
207 Для тех, кто не понял суть квантификаторов, вернёмся к ним снова:
211 Как видите, наше регулярное выражения соответствует одновременно
212 шаблонам „a”, „aaaa” и „aaaaaaaaaaaaaa”. Ключ
\remph{g
} заставляет перл
213 на каждой новой итерации продолжать поиск в текущей строке.
215 \subsubsection{Классы символов
}
217 В регулярных выражениях можно просто создать класс (или группу)
218 символов, перечислив все нужные значки в квадратных скобках. С помощью
219 \remph{—
} можно указать диапазон, как в следующем примере от A до Z. Если
220 тире должно входить в вашу группу, сделайте его первым или последним
225 Наш пример позволяет найти в тексте все слова, начинающиеся с буквы
226 \remph{u
} или любой заглавной буквы английского алфавита.
228 Если содержимое квадратных скобок начинается с символа
\remph{\symbol{94}},
229 значит, на месте этого класса может быть любой символ, кроме тех, которые
234 В нашем случае будут выведены все числа.
236 Пожалуй, это всё, что я расскажу про поиск с помощью регулярных
237 выражений в Perl. Тема обширная и сложная, всего запомнить невозможно.
238 Главное --- понять основы и знать, где подсмотреть. В любом случае,
239 унывать не стоит! Всё будет хорошо.
242 \subsection{Подстановка
}
244 Суть подстановки в том, что мы находим какой-то текст и заменяем его на
245 новый. Хорошей новостью будет то, что искать мы уже умеем. Синтаксис таков:
255 Заменяем на три икса все слова из трёх букв.
256 А вот так можно использовать фрагменты найденного текста против
261 Ещё один пример для закрепления:
265 Этот скрипт выводит кусочек песни Василия Ложкина. В строке девять
266 можно заметить модификатор
\remph{\textbackslash l
}, который переводит
267 следующий за ним символ в нижний регистр. В остальном, все достаточно
268 просто. Подстановка ненамного сложнее поиска.