Анимация
JavaScript
|
Главная Библионтека Некоторые считают, что такая запись снижает удобочитаемость. Мы с ними не согласны. Некоторые говорят, что благодаря этому в программе исчезает необходимость выполнять переход к определению подпрограммы. Но языку Perl все равно. Наше собственное правило гласит; если код не умещается в одной строке или должен использоваться более чем однажды, он оформляется как подпрограмма. Для операции сравнения числовых значений "челнок" есть соответствующая строковая операция - стр*. Эта операция возвращает одно из трех значений в зависимости от результата сравнения двух аргументов по строковым значениям. Вот как можно по-другому записать порядок сортировки, который установлен по умолчанию; Sresult = sort ( $а cmp $b ) Ssomelist; Вам, вероятно, никогда не придется писать именно такую подпрограмму (имитирующую встроенную функцию стандартной сортировки) - если только вы не пишете книгу о Perl. Тем не менее, операция стр все же находит применение в каскадных схемах упорядочивания. Например, вам необходимо расставить элементы по численным значениям, если они численно не равны; при равенстве они должны идти быть упорядочены по строковым значениям. (По умолчанию приведенная выше подпрограмма by number просто ставит нечисловые строки в случайном порядке, потому что при сравнении двух нулевых значений числовое упорядочение провести нельзя.) Вот как можно сказать "числовые, если они численно не равны, иначе строковые"; sub by mostly numeric ( ($а <=> $b) II ($а cmp $b); Этот код работает следующим образом. Если результат работы "челнока" равен -1 или 1, то остальная часть выражения пропускается и возвращается -1 или 1. Если "челнок" дает нуль, то выполняется операция стр, которая возвращает соответствующее значение, сравнивая сортируемые значения как строки. Сравниваются не обязательно те значения, которые передаются в программу. Пусть, например, у вас есть хеш, ключи которого - регистрационные имена, а значения - реальные имена пользователей. Предположим, вы хотите напечатать таблицу, в которой регистрационные и реальные имена будут рассортированы по порядку реальных имен. Сделать это довольно легко. Давайте предположим, что значения находятся в массиве % names. Регистрационные имена, таким образом, представляют собой список keys (%names). Нам нужно получить список регистрационных имен, рассортированных по соответствующим значениям, поэтому для любого конкретного ключа $а мы должны проверить значение $names{$a} и провести Не вполне соответствующая. Встроенная функция sort отбрасывает элементы undef, а эта функция - нет. сортировку относительно данного значения. Если следовать этой логике, то программа практически напишется сама: @sortedkeys = sort by name keys (%names); sub by names f return $names($a) cmp $names($b); foreach (gsortedkeys) { print has a real name of $names($ )\n"; К этому нужно еше добавить "аварийное" сравнение. Предположим, что реальные имена двух пользователей совпадают. Из-за капризной натуры программы sort мы в первый раз можем получить эти значения в одном порядке, а во второй раз - в другом. Это плохо, если данный результат придется, например, вводить в программу сравнения для формирования отчета, поэтому следует избегать таких вещей. Задача легко решается с помощью операции cmp: sub by names i ($namesi$a) cmp $names($b)) ($a cmp $b); Если реальные имена совпадают, то сортировка здесь производится на основании регистрационного имени. Поскольку регистрационные имена уникальны (ведь, помимо всего прочего, они являются ключами хеша, а ключи совпадать не могут), мы можем добиться нужного нам результата. Если вы не хотите, чтобы поздно вечером раздался звонок от системного администратора, удивленно спрашивающего, почему включается аварийная сигнализация - пишите хорошие программы днем! Транслитерация Если вам необходимо взять строку и заменить все экземпляры какого-нибудь символа другим символом или удалить их, это можно сделать, как вы уже знаете, с помощью тщательно подобранных команд s /. Предположим, однако, вам нужно превратить все буквы а в буквы ь, а все буквы b - в буквы а. Это нельзя сделать посредством двух команд s /, потому что вторая команда отменит все изменения, сделанные первой. Такое преобразование данных очень просто выполняется в shell с помощью стандартной команды tiil): tr ab ba <indata >outdata (Если вы ничего не знаете о команде tr, загляните на man-страницу tr( 1); это полезный инструмент.) В Perl тоже применяется операция tr, которая работает в основном так же: tr/ab/ba; 204 Иаучаел1 Perl Операция tr принимает два аргумента: старая строка и новая строка. Они используются так же, как аргументы команды s /; другими словами, имеется некий разделитель, который стоит сразу же за ключевым словом tr и разделяет и завершает аргументы (в данном случае это косая черта, но в этой роли могут выступать почти все символы). Аргументы операции tr похожи на аргументы команды ir(\). Операция tr изменяет содержимое переменной $ (совсем как s /), отыскивая в ней символы старой строки и заменяя найденные символы соответствующими символами новой строки. Вот несколько примеров: = "fred and barney"; tr/fb/bf; # $ теперь содержит "bred and farney" tr/abcde/ABCDE/; # $ теперь содержит "BrED AnD fArnEy" tr/a-z/A-Z/; # $ теперь содержит "BRED AND FARNEY" Обратите внимание на то, что диапазон символов можно обозначить двумя символами, разделенными дефисом. Если вам нужен в строке дефис как таковой, поставьте перед ним обратную косую. Если новая строка короче старой, то последний символ новой строки повторяется столько раз, сколько нужно для того, чтобы строки имели одинаковую длину, например: .$ = "fred and barney"; tr/a-z/x/; # $ теперь содержит "xxxx xxx xxxxxx" Чтобы такое не происходило, поставьте в конце операции tr / букву d, которая означает delete ("удалить"). В данном случае последний символ не повторяется. Все символы старой строки, для которых нет соответствующих символов в новой строке, просто удаляются: 5 = "fred and barney"; tr/a-z/ABCDE/d; # $ теперь содержит "ED AD BAE" Обратите внимание на то, что все буквы, стоящие после буквы е, исчезают, потому что в новом списке соответствующей буквы нет, и на то, что на пробелы это не влияет, потому что их нет в старом списке. По принципу работы это эквивалентно команде tr с опцией -d. Если новый список пуст и опция d не используется, то новый список будет совпадать со старым. Это может показаться глупым - зачем заменять I на I и 2 на 2? - но на самом деле в этом есть довольно глубокий смысл. Операция tr / возвращает количество символов, совпавших со старой строкой, и путем замены символов на самих себя вы можете получить число таких символов, содержащихся в новой строке*. Например: Это справедливо только для одиночных символов. Для подсчета строк в операции сопоставления с образцом используйте флаг /д: while (/образец/g) 1 $count++; 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 |