Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 [ 57 ] 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

Хотя метасимвол \Ъ выше был назван «границей слова», в действительности он определяется как позиция между двумя символами, по одну сторону которой распела! ается \w, а по другую - \W (в любом порядке) - Примеч перев

повысить точность идентификации слов в строке, можно указать то, что окружает слово. Как правило, указываются метасимволы границ, а не пропусков:

/\b([A-Za-2]+\b/ # Обычно наилучший вариант

/\s([A-Za-z]+)\s/ # Не работает в конце строки или без знаков препинания

В Perl существует метасимвол \w, который совпадает с одним символом, разрешенным в идентификаторах Perl. Однако идентификаторы Perl редко отвечают нашим представлениям о словах - обычно имеется в виду последовательность алфавитно-цифровых символов и подчеркиваний, но не двоеточий с апострофами. Поскольку метасимвол \Ь определяется через \w, он может преподнести сюрпризы при определении границ английских слов (и тем более - слов языка суахили).

И все же метасимволы \Ь и \В могут пригодиться. Например, шаблон /\Bis\B/ совпадает со строкой "is" только внутри слова, но не на его границах. Скажем, в thistle совпадение будет найдено, а в vis-a-vis -нет.

1> Смотри также-

Интерпретация \Ь, \w и \s в perlre(l); шаблоны для работы со словами из рецепта 6.23.

6.4. Комментирование регулярных выражений

Проблема

Требуется сделать ваше сложное регулярное выражение более понятным и упростить его изменение в будущем.

Решение

в вашем распоряжении четыре способа: внешние комментарии, внутренние комментарии с модификатором /х, внутренние комментарии в заменяющей части s / и альтернативные ограничители.

Комментарий

Во фрагменте из примера 6.1 использованы все четыре способа. Начальный комментарий описывает, для чего предназначено регулярное выражение. Для относительно простых шаблонов ничего больше не потребуется В сложных шаблонах (вроде приведенного) желательно привести дополнительные комментарии.

Пример 6.1. resname

#1/usr/bm/perl -р

# resname - заменить все имена в стиле foo bar com во входном потоке



6.4. Комментирование регулярных выражений 189

# на foo bar com [204 148 40 9] (или аналогичными)

use Socket, # Загрузить inet addr

s{ #

( й Сохранить имя хоста в $1

С? й Скобки только для группировки

С?! [- ] ) # Ни подчеркивание ни дефис [\w-] + # Компонент имени хоста

\ # и точка домена

) + # Повторяется несколько раз

[A-Za-z] # Следующий символ должен быть буквой

[\w-] + й Завершающая часть домена

) # Конец записи S1

]{ tt Заменить следующим

S1 # Исходная часть плюс пробел

( (Saddr = gethostbyname(Sl)) й Если имеется адрес [ inet ntoa(Saddr) ] # отформатировать

[>}}] tt иначе пометить как сомнительный

}дех й /д - глобальная замена

# /е - выполнение

# /х - улучшенное форматирование

Для эстетов в этом примере использованы альтернативные ограничители. Когда шаблон поиска или замены растягивается на несколько строк, наличие парных скобок делает его более понятным. Другая частая причина для использования альтернативных ограничителей - присутствие в шаблоне символов / (например, s/\/\ \/ \ g) Альтернативные ограничители упрощают чтение такого шаблона (например, si i / /ig или s{ }{/ /}д).

При наличии модификатора /х Perl игнорирует большинство пропусков в шаблоне (в символьных классах они учитываются) и интерпретирует символы # и следующий за ними текст как комментарий Такая возможность весьма полезна, однако у вас могут возникнуть проблемы, если пропуски или символы # являются частью шаблона В таких случаях снабдите символы префиксом \, как это сделано в следующем примере:

s/ # Заменить

\й # знак фунта

(\w+) # имя переменной

\# # еще один знак фунта

/${S1}/xg # значением глобальной переменной

Помните, комментарий должен пояснять программу, а не пересказывать ее. Комментарии типа $i++ # Увеличить $i на 1 станут причиной плохих оценок на курсах программирования или подорвут вашу репутацию среди коллег

Остается модификатор /е, при котором заменяющая строка вычисляется как полноценное выражение Perl, а не как (заключенная в кавычки и интерполированная) строка. Результат выполнения этого кода используется в качестве заменяю-



щей строки. Поскольку выражение будет интерпретировано как программный код, оно может содержать комментарии. Это несколько замедляет работу программы, но не так сильно, как может показаться (пока вы не начали писать собственные тесты, желательно представлять себе эффективность тех или иных конструкций). Дело в том, что правая сторона подстановки проверяется и компилируется на стадии компиляции вместе со всей программой. Для простой замены строк это, пожалуй, перебор, но в более сложных случаях работает просто замечательно.

Удвоение /е напоминает конструкцию aval STRING . Это позволит применить лексические переменные вместо глобальных в предыдущем примере с заменой.

S/ # Заменить

\# # знак фунта

(\w+) # имя переменной

\# # еще один знак фунта

/ $ $1/хеед # значением «любой* переменной

После подстановки /ее проверьте переменную $@ Она содержит сообщения об ошибках, полученные в результате работы вашего кода, - в отличие от /е, в дан-пом случае код деР1ствительно генерируется во время работы программы.

1> Смотри также-

Описание модификатора /х в perlre{i).

6.5. Поиск N-ro совпадения

Проблема

Требуется найти не первое, а N-e совпадение шаблона в строке. Допустим, вы хотите узнать, какое слово предшествует третьему экземпляру слова fish:

One fish two fish red fish blue fish

Решение

Воспользуйтесь модификатором /g и считайте совпадения в цикле while:

$WANT = 3, Scount = О

while (/(\w+)\s+fish\b/gi) { If (++$count == $WANT) {

print The third fish is a $1 one \n ,

tt Предупреждение не выходите из этого цикла с помощью last

The third fish is a red one.

Или воспользуйтесь счетчиком и шаблоном следующего вида:

/С \w+\s+fish\s+){2K\w+)\s+fish/i,



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 [ 57 ] 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242