Анимация
JavaScript
|
Главная Библионтека sub is valicl pattern { my Spat = shift; return eval { " =~ /Spat/; 1 } 11 0, Работа функции основана на том, что при успешном завершении блока возвращается 1. При возникновении исключения этого никогда не произойдет. Комментарий Некомпилируемые шаблоны встречаются сплошь и рядом. Пользователь может поошибке ввести "<Is*[">", *** GET RICH ***" или "+5-i". Если слепо воспользоваться введенным шаблоном в программе, возникнет исключение - как правило, это приводит к аварийному завершению программы. Крошечная программа из примера 6.9 показывает, как проверяются шаблоны. Пример 6.9. paragrep #/usr/bin/perl # paragrep - простейший поиск die "usage: $0 pat [files]\n" unless (s>ARGV, $/ = ; Spat = shift; eval { "" =" /Spat/, 1 } or die SO: Bad pattern Spat $(s>\n, while (<>) { print "SARGV $ : S " if /$pat/o; Модификатор /о обещает Perl, что значение интерполируемой переменной останется постоянным во время всей работы программы - это фокус для повышения быстродействия. Даже если значение $pat изменится, Perl этого не заметит. Проверку можно инкапсулировать в фун1одии, которая возвращает 1 при успешном завершении блока и О в противном случае <см. выше функцию is valid pattern). Хотя исключение можно также перехва/ить с помощью eval "/$pat/, у такого решения есть два недостатка. Во-первых, во введенной пользователем строке не должно быть символов / (или других выбранных ограничителей). Во-вторых, в системе безопасности открывается зияющая брешь, которую было бы крайне желательно избежать. Некоторые строки могут сильно испортить настроение: Spat = "You lose @{[ system(rm -rf *)]) big here". Если вы не желаете предоставлять пользователю настоящие шаблоны, сначала всегда можно выполнить метапреобразование строки: $safe pat = quotemeta($pat), somethingO if /Ssafe pat/; Или еще проще: somethingO if /\Q$pat/, 6.12. Локальный контекст в регулярных выражениях 207 Но если вы делаете нечто подобное, зачем вообще связываться с поиском по шаблону? В таких случаях достаточно простого применения index. Разрешая пользователю вводить настоящие шаблоны, вы открываете перед ним много интересных и полезных возможностей. Это, конечно, хорошо. Просто придется проявить некоторую осторожность, вот и все. Допустим, пользователь желает выполнять поиск без учета регистра, а вы не предусмотрели в своей программе параметр вроде -i в grep. Работая с полными шаблонами, пользователь сможет ввести внутренний модификатор /i в виде Ci) - например, /(i)stuff/. Что произойдет, если в результате интерполяции получается пустая строка? Если $pat - пустая строка, с чем совпадет /$раТ/ - иначе говоря, что произойдет при пустом поиске ? С началом любой возможной строки? Неправильно. Как ни странно, при поиске по пустому шаблону повторно используется шаблон предыдущего успешного поиска. Подобная семантика выглядит сомнительно, и ее практическое использование в Perl затруднительно. Даже если шаблон проверяется с помощью eval, учтите: время поиска по некоторым шаблонам связано с длиной строки экспоненциальной зависимостью. Надежно идентифицировать такие шаблоны не удается. Если пользователь введет один из них, программа надолго задумается и покажется «зависшей». Возможно, из тупика можно выйти с помощью установленного таймера, однако в версии 5.004 прерывание работы Perl в неподходящий момент может привести к аварийному завершению. > Смотри также- Описание функции eval в perlfunc(\). 6.12. Локальный контекст в регулярных выражениях Проблема Требуется преобразовать регистр в другом локальном контексте или заставить метасимвол \w совпадать с символами национальных алфавитов - например, Jose или dejd vu. Предположим, у вас имеется полгигабайта текста на немецком языке, для которого необходимо составить предметный указатель. Вы хотите извлекать слова (с помощью \w+) и преобразовывать их в нижний регистр (с помощью 1с или \L). Однако обычные версии \w и 1с не находят слова немецкого языка и не изменяют регистр символов с диакритическими знаками. Решение Регулярные выражения и функции обработки текста Perl имеют доступ к локальному контексту POSIX. Если включить в программу директиву use locale, Perl позаботится о символах национальных алфавитов - конечно, при наличии разумной спецификации LC CTYPE и системной поддержки. use locale, Комментарий По умолчанию \w+ и функции преобразования регистра работают с буквами верхнего и нижнего регистров, цифрами и подчеркиваниями. Преобразуются лишь простейшие английские слова, и даже в очень распространенных заимствованных словах происходят сбои. Директива use locale помогает справиться с затруднениями. Пример 6.10 показывает, чем отличаются выходные данные для английского (en) и немецкого (de) локальных контекстов. Пример 6.10. localeg #i/usr/bin/perl -w tt localeg - выбор локального контекста use locale, use POSIX locale h , $naroe = andreas k\xF6nig , @locale{qw(German English)) = qw(de DE IS0 8859-1 us-ascii), setlocale(LC CTYPE, $locale{English}) or die Invalid locale $locale{English} , @english names = (), while (Sname =~ /\b(\w+)\b/g) ( push(@english names, ucfirst(SI)), setlocale(LC CTYPE, $locale{German}) or die Invalid locale Slocale(German} , @german names = (), while (Sname =- /\b(\w+)\b/g) { push(@german names, ucfirst(SI)), print English names @english names\n , print German names @german names\n , English names: Andreas К Nig German names: Andreas KOnig Решение основано на поддержке локальных контекстов в P0S1X. Ваша система может обладать, а может и не обладать такой поддержкой. Но даже если система заявляет о поддержке локальных контекстов POSIX, в стандарте не определены имена локальных контекстов. Разумеется, переносимость такого решения не гарантирована. t> Смотри также- Описание метасимволов \Ь, \w и \s в perlre(i), описание локальных контекстов Perl вperllocale(\) и странице руководства locale(3) вашей системы; рецепт 6.2. 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 |