Анимация
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

print "$2 overlaps in $1-$2-$3\n";

body overlaps in no-body-snatcher

Казалось бы, из-за наличия максимального квантификатора переменная $1 должна захватывать все содержимое "nobody". В действительности так и происходит - на некоторое время. Но после этого не остается ни одного символа, который можно было бы занести в $2. Механизм поиска дает задний ход, и $1 неохотно уступает один символ переменной $2. Пробел успешно совпадает, но далее в шаблоне следует переменная \2, которая в настоящий момент содержит просто "у". Следующий символ в строке - ие "у", а "Ь". Механизм поиска делает следующий шаг назад; через некоторое время $1 уступит $2 достаточно символов, чтобы шаблон нашел фрагмент, пробел и затем тот же самый фрагмент.

Этот прием не работает, если само перекрытие содержит повторяющиеся фрагменты - как, например, для строк "rococo" и "cocoon". Приведенный выше алгоритм решит, что перекрываются символы "со", а не "coco". Однако мы хотим получить не "госососооп", а "гососооп". Задача решается включением минимального квантификатора в $1:

/"(\w+)(\w+) \2(\w+)$/

Трудно представить, насколько мощными возможностями обладают обратные ссьшки. Пример 6.11 демонстрирует принципиально новый подход к проблеме разложения числа на простые множители (см. главу 2 «Числа).

Пример 6.11. prime-pattern

#i/usr/bin/perl

# prime pattern - разложение аргумента на простые множители по шаблону for ($N = Со X shift); $N =- /-(оо+)\1+$/, $N =" s/$1/o/g) {

print length($1), " ";

print length ($N), "\n";

Несмотря на свою непрактичность, этот подход отлично демонстрирует возможности обратных ссылок и потому весьма поучителен.

Приведем другой пример. Гениальная идея, предложенная Дугом Макилро-ем (Doug Mcllroy) - во всяком случае, так утверждает Эндрю Хьюм (Andrew Hume), - позволяет решать диофантовы уравнения первого порядка с помощью регулярных выражений. Рассмотрим уравнение 12х + 15у + 16z = 281. Сможете ли вы найти возможные значения х, у и z? А вот Perl может!

# Решение 12х + 15у + 16z = 281 для максимального х If (($Х, $У, $Z) =

(( о X 281) =- /"(0.)\1{11}(о.)\2{14}(о.)\3{15}$/))

($х, $у, $2) = (length($X), length($Y), length($Z)); print "One solution is- x=$x, y=$y; z=$z.\n", } else {

print "No solution.\n";

One solution is: x=17; y=3; z=2.



Поскольку для первого о* ищется максимальное совпадение, х растет до максимума. Замена одного или нескольких квантификаторов * на + или + дает другие решения:

(( о X 281) =- /-(о+)\1{11}(о+)\2{14}(о+)\3{15}$/))

One solution is: х=17; у=3; z=2.

(( о X 281) =- Г(о.?)\1{11}(о.)\2{14}(о.)\3{15}$/))

One solution is: х=0; у=17; z=11.

(( о X 281) =- /•(о+?)\1{11}(о.)\2{14}(о.)\3{15}$/))

One solution IS х=1; у=3; z=14.

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

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

Описание обратных ссылок в разделе «Regular Expressions* perlre(i).

6.17. Логические AND, OR и NOT в одном шаблоне

Проблема

Имеется готовая программа, которой в качестве аргумента или входных данных передается шаблон. В нее невозможно включить дополнительную логику - например, параметры для управления учетом регистра при поиске, AND и NOT. Следовательно, вы должны написать один шаблон, который будет совпадать с любым из двух разных шаблонов (OR), двумя шаблонами сразу (AND) или менять смысл поиска на противоположный (NOT).

Подобная задача часто возникает при получении данных из конфигурационных файлов, Web-форм или аргументов командной строки. Пусть у вас имеется программа, в которой присутствует следующий фрагмент:

chomp($pattern = <C0NFIG FH>), If ( $data =" /$pattern/ ) { }

Если вы отвечаете за содержимое CONFIG FH, вам понадобятся средства для передачи программе поиска логических условий через один-единственный шаблон.

Решение

Выражение истинно при совпадении /ALPHA/ или /ВЕХА/ (аналогично /ALPHA/ 11 / BETA/):

/ALPHA I BETA/



6.17. Логические AND, OR и NOT в одном шаблоне 217

Выражение истинно, если и /ALPHA/, и /ВЕТА/ совпадают при разрешенных перекрытиях (то есть когда подходит строка BETALPHA ). Аналогично /ALPHA/ && / BETA/:

/-(?=.ALPHA)(= .BETA)/s

Выражение истинно, если и /ALPHA/, и /ВЕТА/ совпадают при запрещенных перекрытиях (то есть когда BETALPHA не подходит):

/ALPHA .SETA(BETA .ALPHA/s

Выражение истинно, если шаблон /РАТ/ не совпадает (аналогично $var ~ /РАТ/): /-(? (iPAT) ).$/s

Выражение истинно, если шаблон BAD не совпадает, а шаблон GOOD - совпадает: /(•?=-(? (71 BAD) ).$)GOOD/s

Комментарий

Предположим, вы пишете программу и хотите проверить некоторый шаблон на несовпадение. Воспользуйтесь одним из вариантов:

if (i($string = /pattern/)) {somethingO } # Некрасиво if ( Sstring /pattern/) {somettiingO } « Рекомендуется

Если потребовалось убедиться в совпадении обоих шаблонов, примените следующую запись:

if (Sstring =" /pati/ && Sstring = /pat2/ ) { somethingO }

Проверка совпадения хотя бы одного из двух шаблонов выполняется так:

if (Sstring =" /pati/ Sstring = /pat2/ ) { somethingO }

Короче говоря, нормальные логические связки Perl позволяют комбинировать логические выражения вместо того, чтобы объединять их в одном шаблоне. Но давайте рассмотрим программу minigrep из примера 6.12, которая в качестве аргумента получает всего один шаблон.

Пример 6.12. minigrep

#/usr/bin/perl

# minigrep - тривиальный поиск Spat = shift, while (О) {

print if /$pat/o,

Если потребуется сообщить minigrep, что некоторый шаблон не должен совпадать или что должны совпасть оба мини-шаблона в произвольном порядке, вы оказываетесь в тупике. Программа просто не предусматривает подобных конструкций. Как сделать все в одном шаблоне? Другими словами, вы хотите выполнить программу minigrep с параметром РАТ, который не совпадает или содержит несколько логически связанных шаблонов. Такая задача нередко возникает в программах, читающих шаблоны из конфигурационных файлов.



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