Анимация
JavaScript
|
Главная Библионтека Проблема с OR решается просто благодаря символу альтернативного выбора I. Однако AND и OR потребуют особого кодирования. В случае с AND придется различать перекрывающиеся и неперекрывающиеся совпадения. Допустим, вы хотите узнать, совпадают ли в некоторой строке шаблоны bell и lab . Если разрешить перекрытия, слово labelled пройдет проверку, а если отказаться от перекрытий - нет. Случай с перекрытиями потребует двух опережающих проверок: labelled =" /"(= .bell)C?= .lab)/s Помните- в нормальной программе подобные извращения не нужны. Достаточно сказать: Sstring =" /bell/ && Sstring =" /lab/ Мы воспользуемся модификатором /х с комментариями. Развернутая версия шаблона выглядит так: if ($murray hill =" m{ # Начало строки (г # Опережающая проверка нулевой ширины • # Любое количество промежуточных символов bell # Искомая строка bell ) # Вернуться, мы лишь проверяем (= # Повторить . # Любое количество промежуточных символов lab # Искомая строка labs }sx ) # /8 разрешает совпадение с переводом строки print Looks like Bell Labs might be in Murray Hill\n , Мы не воспользовались * для раннего завершения поиска, поскольку минимальный поиск обходится дороже максимального. Поэтому для произвольных входных данных, где совпадение с равной вероятностью может произойти как в начале, так и в конце строки, * будет эффективнее нашего решения. Разумеется, выбор между * и * иногда определяется правильностью программы, а не эффективностью, но не в данном случае. Для обработки перекрывающихся совпадений шаблон будет состоять из двух частей, разделенных OR. В первой части lab следует после bell , а во второй - наоборот: labelled = /С " .bell .lab)! " .lab .bell)/ или в развернутой форме: Sbrand = labelled , If (Sbrand m{ ( # Группировка без сохранения " .J # Любое количество начальных символов bell # Искомая строка bell tt Любое количество промежуточных символов 6.17. Логические AND, OR и NOT в одном шаблоне 219 lab # Искомая строка lab ) # Конец группировки I # Или попробовать другой порядок С? # Группировка без сохранения ~ # Любое количество начальных символов lab # Искомая строка lab # Любое количество промежуточных символов bell # Искомая строка bell ) # Конец группировки }sx ) # /s разрешает совпадение с переводом строки print Our brand has bell and lab separate \n , Такие шаблоны не всегда работают быстрее. $murray hill =" /bell/ && $murray hiUe =~/1аЬ/ сканирует строку не более двух раз, однако для (=" *bell)(=" ♦lab) механизм поиска ищет lab для каждого экземпляра bell , что в наихудшем случае приводит к квадратичному времени выполнения. Тем, кто внимательно рассмотрел эти два случае, шаблон NOT покажется тривиальным. Обобщенная форма выглядит так; $тар =" /"С Ciwaldo) )*$/s То же в развернутой форме: if ($map =" m{ # Начало строки С? # Группировка без сохранения С # Опережающая отрицательная проверка waldo # Нашли впереди ) # Если да, отрицание не выполняется # Любой символ (благодаря /s) ) * # Повторить группировку О и более раз $ # До конца строки }sx ) # /s разрешает совпадение с переводом строки print There s no waldo here\n , Как объединить в одном шаблоне AND, OR и NOT? Результат выглядит отвратительно, и в обычных программах делать нечто подобное практически никогда не следует. Однако при обработке конфигурационных файлов или командных строк, где вводится всего один шаблон, у вас нет выбора. Объедините все изложенное выше. Будьте осторожны. Предположим, вы хотите запустить программу UNIX w и узнать, зарегистрировался ли пользователь tchrist с любого терминала, имя которого начинается не с ttyp; иначе говоря, шаблон tchrist должен совпадать, а "ttyp - нет. Примерный вывод w в моей системе Linux выглядит так: 7:15ain up 206 days, 13:30, 4 users, load average: 1.04, 1.07, 1.04 USER TTY FROM LOGINe IDLE JCPU PCPU WHAT tchrist ttyl 5:16pin 36day8 24:43 0.03s xinlt tchrist tty2 5;19pm 6days 0.43s 0.43s -tcsh tchrist ttypO chthon 7;58am Sdays 23.44s 0.44s -tcsh gnat ttys4 coprollth 2:01pm 13;36m 0.30s 0.30s -tcsh Посмотрим, как поставленная задача решается с помощью приведенной выше программы minigrep или программы tcgrep, приведенной в конце главы: % W I minigrep "Ci *ttyp) .tchrist Расшифруем структуру шаблона: # Привязка к началу строки С?! # Опережающая проверка нулевой ширины . # Любое количество любых символов (быстрее ttyp # Строка, которая не должна находиться ) # Опережающая отрицательная проверка, возврат к началу . # # Любое количество любых символов (быстрее *) tchrist # Пытаемся найти пользователя tchrist Неважно, что любой нормальный человек в такой ситуации дважды вызывает grep (из них один - с параметром -v, чтобы отобрать несовпадения): % W I grep tchrist grep -v ttyp Главное - что логические конъюнкции и отрицания можно закодировать в одном шаблоне. Однако подобные вещи следует снабжать комментариями - пожалейте тех, кто займется ими после вас. Как внедрить модификатор /s в шаблон, передаваемый программе из командной строки? По аналогии с /1, который в шаблоне превращается в (i). Модификаторы /s и /т также безболезненно внедряются в шаблоны в виде /(s) или /Cm). Их даже можно группировать - например, /(smi). Следующие две строки фактически эквивалентны: % grep -1 ШАБЛОН ФАЙЛЫ % minigrep (1)ШАБЛ0Н ФАЙЛЫ Е> Смотри также- Описание опережающих проверок в разделе «Regular Expressions* perlre(iy, man-страницы grep(i) и ®(1) вашей системы. Работа с конфигурационными файлами рассматривается в рецепте 8.16. 6.18. Поиск многобайтовых символов Проблема Требуется выполнить поиск регулярных выражений для строк с многобайтовой кодировкой символов. Кодировка определяет соответствие между символами и их числовыми представлениями. В кодировке ASCn каждый символ соответствует ровно одному 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 |