Готовый перевод sed & awk / sed & awk: 3.2 Наборы символов

Внимание! Этот перевод, возможно, ещё не готов, так как модераторы установили для него статус «перевод редактируется»

Мы имеем два базовых элемента выражения:

1. Значение, выраженнное буквально или переменная

2. Оператор

Регулярное выражение состоит из тех же элементов. Любой символ, исключая спецсимволы из таблицы 3.1 интерпретируется буквально и удовлетворяеттолько самому себе.

Значения спецсимволов

. Удовлетворяет любому одиночному символу, исключая новую строку. В awk, точка может также удовлетворять и новой строке.

* Удовлетворяет любому количеству (включая ноль) одиночных символом ( включая символы указанные в регулярном выражении) которе непосредственно предшествуют.

[...] Удовлетворяет любому классу символом в скобках. Символ (^) как первый символ внутри скобок меняет условие совпадения для всех символов, кроме новой строки и перечисленных в классе. В awk, новая строка также удовлетворяет. Дефис (-) используется для задания диапозона символов. Закрывающуяся скобка (]), как первый символ в классе, будет частью класса. Все остальные спецсимволы теряют свое значение, когда указан член класса.

^ Первый символ регулярного выражения, удовлетворяет началу строки. Удовлетворяет началу строки в awk, даже если строка содержит перевод строки.

$ как символ регулряного выражения, удовлетворяет концу строки. Удовлетворяет концу строки в awk, даже если содержит окончание строки.

\{n,m\} Удовлетворяет дипозону вхождений одиночных символов ( включая символы регулярных выражений) которые ему предшествуют. \{n\} будет соответствовать только n, \{n,\} ,будет соответстовать по крайней мере n событий, и \{n,m\} будет соответствовать любому числу вхождений между n и m. (sed и grep не будут в очень старых версиях.)

\ Эскейп, спецсимвол, который описан ниже.

Таблица 3.1 Обзор спецсимволов

Расширенные символы (egrep и awk)

Значения спецсимволов

+ Удовлетворяет одному или нескольким вхождениям предыдущего регулярного выражения

? Удовлетворяет нулю или нескольким вхождениям предыдущего регулярного выражения

| Указывает на то, что совпадение может быть как до, так и после регулярного выражения(чередование).

() Группы регулярных выражений.

{n,m} Удовлетворяет диапозону вхождений одного символа (включая символ заданный в регулярном выражении) который ему непосредственно предшествует. {n} соответствует числу вхождений, {n,} соответствует, по крайней мере n вхождений, и {n,m} соответствует количеству вхождений между n и m. (POSIX agrep и POSIX awk, не являются традиционными egrep и awk.) [2]

[2] Большинство awk версий awk не поддерживают этот способ.

Спецсимволы имеют особое значение в регулярных выражения, так же, как + и * имеют особое значение в арифметических выражениях. Некоторые из спесимволом (+ ? () |) доступны только как часть для расширения параметров, используемых такой программой как egrep и awk. Мы рассмотрим, что каждый спецсимвол делает в следующем разделе, начнем с бэкслеша.

3.2.1 Вездесущий бэкслеш

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

\. Бэкслеш обычно используют для troff запроса или макроса, который начинается с точки.

\.nf С помощью бэкслеша, Вы так же можете исключить бэкслеш. Для примера, смена шрифта в troff "\f". Для происка строк, содержащих запрос, Вы используете следующее выражение:

\\f В добавление sed использует бэкслеш для вызова группы обычных символов как спецсимволов, как будет показано на таблице 3.2.

Таблица 3.2: Исключающие спецсимволы в sed

n в конструкции "\n" представляет цифру от 1 до 9; его использование будет объяснено в Главе 5, Основные команды sed.

3.2.2 Подстановка

Подстановка спецсимвола или точки (.) можно прировнять к переменной. Переменная представляет любое значение в арифметическом выражении. В регулярном выражении точка (.) подставляет любой символ, исключая новую строку. ( В awk точка может быть и символом новой строки.)

Учитывая, что мы можем описывать последовательности символом, подстановка символов позволяет Вам указать позицию, которую любой символ может занимать.

Для примера, если мы ищем файл, содержащий обсуждение новой линейки микропроцессоров Intel, регулряное выражение будет следующим:

80.86

будут соответствовать строки, содержащие ссылки на "80286," "80386," или "80486."[3] Для поиска точки, Вам следует перед точкой поставить бэкслеш.

Линейка микропроцессоров Pentium нарушает наши простые поисковые эксперименты и портит веселие. Не говоря уже о оригинальном 8086.

Это редко бывает полезно для соответствия любому символу в начале или конце шаблона. Таким образом подстановочный символ предшествует или следует после обысного символа или спецсимвола. Для примера, регулряное выражение может быть написано для поиска ссылки на главу:

Chapter.

Они ищет "строку 'Chapter' с любым последующим символом." В поиске это выражение может оказаться таким же как и фиксированная строка "Chapter". Рассмотрим следующий пример:

$ grep 'Chapter.' sample

you will find several examples in Chapter 9.

"Quote me 'Chapter and Verse'," she said.

Chapter Ten

Поисковая строка "Chapter" сопоставляется с "Chapter." будет соответствовать тем же строкам. Как правило в одном случае они будут разными - если "Chapter" будет в конце строки. Подстановка не соответствует новой строке, таким образом "Chapter." не будет соответствовать этой строк,хотя фиксированный шаблон будет.

3.2.3 Написание регулярных выражений

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

Другими словами, местом для исправления проблемы, будет выражение в котором Вы описываете желаемый результат. Или выражение неокончено или неправильно сформировано. Для примера, если программа обработает это выражение:

PAY = WEEKLY_SALARY * 52

и зная значения этих переменных, она расчитает правильный результат. Но кто-то может возразить, что формула не учитывает продавцов, которые также получают комиссию. Для объяснения этого примера, выражение должно быть сформулировано так:

PAY = WEEKLY_SALARY * 52 + COMMISSION

Вы можете сказать, что то, кто написал первое выражение, не полностью понимает сферу проблем, таким образом не описал ее правильно. Важно знать, насколько подробным описание должно быть. Если Вы кого-нибудь попросите подать Вам книгу, и в поле зрения будет несколько книг, то Вам нужно будет описать более подробно, какую именно книгу Вы хотите (или довольствоваться случайным процессом выбора).

Это же справедливо и для регулярных выражений. Программа, такая как grep, проста и легка в использовании. Понимание элементов регулярных выражений не столь трудно. Регулярные выражения позволяют Вам писать простые и полные описания шаблона. Как правило, при написании регулярных выражений сложным( и интересным) является их применение: разнообразие событий или условий в которых применяется шаблон. Эта сложность присуща самому языку, так же как не всегда можно понять смысл выражения, поиском каждого слова в словаре.

Процесс написания регулярного выражения включает в себя три шага:

1. Понимание того, что Вы хотите найти и как это применить в тексте.

2. Написание шаблона для поиска.

3. Проверка шаблона, для проверки, чему он соответствует.

Этот процесс практически такой же, как и написание программы программистом. Шаг 1 может быть просмотром спецификации, которая должна отражать понимание, что проблема будет решена и как ее решить. Шаг 2 аналогичен написанию кода программы и Шаг 3 запуск программы и ее тестирование согласно спецификации. Шаг 2 и 3 выполняются до тех пор, пока программа не заработает соответствующим образом.

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

Hits

Искомая строка.

Misses

Строка, которую я не хочу найти.

Omission

Строка, которую я не нашел, но хотел.

False alarms

Строка которую я нашел, но не хотел.

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

Трудности особенно очевидны, когда Вы должны описать шаблон используя фиксированные строки. Каждый символ, удаляемый из шаблона с фиксированной строкой увеличивает количество возможных совпадений. Например, во премя поиска строки "what", Вы решаете, что хотели бы находить так же "What". Единственный фиксированный шаблон, который будет соответствовать "What" и "what" это "hat", самая длинная строка, общая для обоих. Очевидно, что поиск "hat" выдаст значительное количество нежелательных результатов. Каждый добавляемый Вами символ в фиксированный шаблон уменьшает количество возможных совпадений. Строка "them" обычно выдаст меньше совпадений, чем строка "the".

Использование спецсимволов в шаблоне представляет огромную гибкость в расширении или сужении диапозона совпадений. Спецсимволы, используемые в группе с буквами или другими спецсимволами, могут быть использованы для расширения диапозона совпадений, и исключая нежелательные совпадения.

3.2.4 Классы символов

Класс символов является уточнение концепции подстановки. Вместо поиска любого символа на конкретной позиции, мы можем указать список символов. Спецсимвол квадратные скобки ([]) включает список символов, каждый из которых может занять одиночную позицию.

Классы символов полезны при буквах в верхнем и нижнем регистрах, например. Если "what" может встретиться как с заглавной буквы так и со строчной, Вы можете указать:

[Ww]hat

Это регулярное выражение удовлетворяет "what" или "What". Оно будет соответствовать любой строке, которая содержит эту четырех символьную строку, первый символ в которой или "W" или "w". Таким образом, оно может соответствовать "Whatever" или "somewhat."

Если файл содержит структурированные заголовки макросов, такие как .H1, .H2, .H3, и т.д., Вы можете извлеч любую из этих строк, с помощью регулярного выражения:

\.H[12345]

Этот шаблон трехсимвольной строки, в которой последний символ может быть любой цифрой от 1 до 5.

Такой же синтаксис используется в Unix шелле. Таким образом, Вы можете использовать классы символов для указания имен файлов в командах UNIX. Для примера, для извлечения заголовка из группы файлов глав, Вы можете ввести:

$ grep '\.H[123]' ch0[12]

ch01:.H1 "Contents of Distribution Tape

ch01:.H1 "Installing the Software"

ch01:.H1 "Configuring the System"

ch01:.H2 "Specifying Input Devices"

ch01:.H3 "Using the Touch Screen"

ch01:.H3 "Using the Mouse"

ch01:.H2 "Specifying Printers"

ch02:.H1 "Getting Started"

ch02:.H2 "A Quick Tour"

Запомните, что шаблон следует заключать в ковычки, иначе он попадет в grep быстрее, чем будет обработан шеллом. Вывыд, сгенерированый grep, показывает имя файла для каждой печатаемой строки. Для другого примера класса символов, предположим, что Вы указываете разные знаки пунктуации которыми заканчивается предложение:

.[!?;:,".].

Это выражение удовлетворяет "любому символу, за которым следует восклицательный знак или знак вопроса или точка с запятой или двоеточие или запятая или кавычка или точка и затем два пробела и любой символ." Оно может быть использовано для поиска мест, где два пробела между концом одного предложения и началом следующего предложения, когда они идут в одной строке. Обратите внимание, на три точки в этом выражении. Первая и последняя точки являются подстановочными спецсимволами, но вторая точка обрабатывается буквально. Внутри квадратных скобок стандартные спецсимволы теряют свои свойства. Таким образом, точка внутри квадратных скобок является просто точкой. Таблица 3.2 список символов, которые имеют особое значение внутри квадратных скобок.

Символ Функция

\ Исключает любой специальный символ (только awk)

- Указвает диапозон, когда не на первой или последней позиции.

^ Указывает на инверсию шаблона, только когда на первой позиции.

Table 3.2: Специальный символы в классах символов

Бэкслеш является специальным только в awk, он дает возможность написать "[a\]1]", для класса символов, который соответствует а и закрываютщейся квадратной скобке или а и 1

3.2.4.1 Диапозоны символов

Дефис (-) позволяет указать диапозон символов. Для примера, диапозон всех английских букв в верхнем регистре[4] может быть указан так:
[A-Z]

[4] Это может быть довольно беспорядочно работать, когда используется не ASCII набор символов и/или язык отличный от английсткого. POSIX решает данную проблему; новые возможности POSIX представлены далее.

Диапозон одиночных цифр может быть представлен как:
[0-9]

Этот класс символов помог решить проблему с шаблоном ссылок на главы. Рассмотрим следующее регулярное выражение:

[cC]hapter [1-9]

Оно удовлетворяет строке "chapter" или "Chapter", за которой следует пробел и затем любая одиночная цифра от 1 до 9. Каждая из следующих строк удовлетворяет шаблону:

you will find the information in chapter 9

and chapter 12.

Chapter 4 contains a summary at the end.

В зависимости от задачи, вторая строка в этом примере может выдавать ложные срабатывания. Вы можете добавить следующий диапозон "[1-9]" для избежания соответсвия двузначным числам. Вам следует указать сласс символов, чтобы не соответствовать на той позиции, как мы увидим в следующем разделе. Множественные диапозоны могут быть указаны так же, как и буквенные символы:

[0-9a-z?,.;:'"]

Это выражение будет соответствовать "любому одиночному символу, который является цифрой, буквой в нижнем регистре или знаком вопроса, запятой, точкой, точкой с запятой, двоеточие, одиночкая кавычка или двойная кавычка". Запомните, что каждый символ класса удолетворяет одному символу. Если вы укажете несколько классов, Вы укажите множественную последовательность символов, такую как:

[a-zA-Z][.?!]

Это выражение будет соответствовать "любая букава в верхнем или нижнем регистре, за которой следует точка, знак вопроса или восклицательный знак".

Закрывающаяся скобка обрабатывается как член класса если она встречается как первый символ класса (или как первый символ после циркумфлекса; смотреть следующий раздел). Дефис теряет свое специальное значение, если он первый или последний символ. Таким образом, для соответствия арифметическому оператору, мы помещаем дефис (-) первым в следующем примере:

[-+*/]

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

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

MM-DD-YY

MM/DD/YY

Следующее регулряное выражение показывает возможности диапозона значений для каждой позиции символа:

[0-1][0-9][-/][0-3][0-9][-/][0-9][0-9]

Либо "-" или "/" могуть бычть разделителями. Помещая дефис на первую позицию гарантирует, что он как обычный символ, как дефис и не будет означать диапозон.[5]

[5] Обратите внимание, что выражение удовлетворяет дате, в которой встречаются разделители, так же не возможна дата вида "15/32/78".

3.2.4.2 Исключение класса символов.

Обычно, классы символов включают все символы, которые Вы хотите найти на заданной позиции. Циркумфлекс (^), как первый символ в классе исключает все символы в классе с начала шаблона. Вместо любого символа ожидается новая строка[6], которая не входит в список в квадратных скобках. Следующий шаблон будет соответствовать любому не цифровому символу:

[6] В awk, новая строка так же включена в шаблон.

[^0-9]

Он соответствует всем заглавным или прописным буквам алфавита и всем специальным символам, таким как знаки препинания.

Исключение некоторых символов иногда удобней, чем точный список всех символов, которые Вы хотите найти. Для примера, если Вы хотите найти любую константу, Вы можете просто исключить гласные:

[^aeiou]

Это выражение будет удовлетворять любой константе, любой заглавной гласной и любому знаку пунктуации или спецсимволу.

Взлянем на следующее регулярное выражение:

\.DS "[^1]"

Это выражение удовлетворяет строке ".DS" за которой следует пробле, затем кавычка, затем любой символ исключая цифру "1" и затем еще кавычка. [7] Это сделано чтобы исключить попадания в следующую строку:

[7] Когда набираете шаблон в командной строке, убедитесь в закрытии одиночных кавычек. Символ ^ специальный в оригинальном Bourne shell.

.DS "1"

в то время как удовлетворяющие строки следующие:

.DS "I"

.DS "2"

Этот синтаксис так же может быть использован для уменьшения степени совпадений, как мы покажем далее.

3.2.4.3 Дополнения классов символов POSIX

Стандарт POSIX формализует значение символов регулярных выражений и операторов. Стандарт описывает два класса регулярных выражений: Основные Регулярные Выражения(BREs), которые используются grep и sed, и Расширенные Регулярные Выражения, которые используются в egrep и awk.

Для распространения в не только английской среде, POSIX стандарт увеличивает возможности классов символов для поиска символов не английского алфавита. Для примера, французская è это алфавитный символ, но стандартный класс [a-z] его не найдет. Дополнительно стандарт предусматривает последовательность символов, которая должна рассматриваться как единое целое, когда идет поиск и сбор(сортировка) данных в строке.

POSIX так же меняет общие термины. То, что мы называем "класс символов" называется "выражение в скобках" в стандарте POSIX. Выражения в скобках, кроме буквенных, таких как a, !, и так далее, Вы можете получить дополнительные компоненты. Такие как:

Классы символов. Классы символов POSIX состоят из ключевого слова в скобках [: и :]. Ключевые слова описывают разные классы символов, такие как буквы алфавита, управляющие символы и т.д. (см. таблица 3.3).

Сопоставление символов. Сопоставление символов представляет собой многосимвольную последовательность, которая обрабатывается как единое целое. Оно состоит из символов, ограниченных скобками [. и .].

Эквивалентные классы. Эквивалентный класс представляет набор символов, который содержит эквиваленты, тикие как e и è. Он соделжит проименованные элементы языка, ограничивается скобками [= и =].

Эти три конструкции должны применяться в вадратных скобок внутри скобочного выражения. Для примера [[:alpha:]!] соответствует одиночному символу алфавита или воскличательному знаку, [[.ch.]] соответствует упорядоченному элементу ch, но не соответствует только букве c или букве h. В французском [[=e=]] может соответствовать e, è, или é. Классы и соответствия показыны в таблице 3.3.

Класс Соответствующие символы

[:alnum:] Печатаемые символы (включая пробел)

[:alpha:] Буквы алфавита

[:blank:] Пробел или табуляция

[:cntrl:] Управляющие символы

[:digit:] Числовые символы

[:graph:] Печатаемсые и видимые символы ( не пробел)

[:lower:] Символы в нижнем регистре

[:print:] Буквенно-цифровые символы

[:punct:] Символы пунктуации

[:space:] Пробел

[:upper:] Символы в верхнем регистре

[:xdigit:] Шестнадцатеричные символы

Table 3.3: Классы символо POSIX

Эти особенности медленно интегрируются в коммерческие версии sed и awk, как производители полностью реализуют стандарт POSIX. GNU awk и GNU sed поддерживают обозначачения классов символов, но не другие два скобочных обозначения. Обратитесь к документации Вашей системы для проверки доступностей данных возможностей.

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

3.2.5 Повторные вхождения символа.

Спецсимвол звездочка (*) показывает, что обрабатываемое регулярное выражение может встретиться ноль и более раз. Таким образом, если он изменит один символ, символ может быть там или нет, их может быть больше чем один. Вам следует использовать звездочку для поиска слова, которое может встречаться в кавычках.

"*hypertext"*

Слово "hypertext" будет найдено, внезависимости в кавычках оно или нет.

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

1

5

10

50

100

500

1000

5000

Регулярное выражение

[15]0*

будет соответсвовать всем строка, в то время как регулярное выражение

[15]00*

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

*

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

".*"

Это будет соответствовать все символам между первой и последней кавычкой и плюс сами кавычки. Все что удовлетворяет ".*" всегда максимально полное. Сейчас это может выглядень не очень важным, но станет, когда вы изучите замену найденой строки.

Другим примером квадратных скобок является общее обозначение инструкций форматирования в языках разметки, таких как SGML, HTML и Ventura Publisher.

Вы можете напечатать все строки с такими кавычками указав:

$ grep '<.*>' sample

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

I can do it

I cannot do it

I can not do it

I can't do it

I cant do it

Если мы хотим найти каждую форму негативного выражения, но не позитивного выражения, следующее регулярное выражение сделает это:

can[no']*t

Звездочка указывает, что любой символ в классе может соответствовать в любом порядке и любой количество раз. Вот он:

$ grep "can[no']*t" sample

I cannot do it

I can not do it

I can't do it

I cant do it

Здесь четыре результата и пропущенно одно положительное выражение. Запомните, что регулярное выражение пробует найти любое число символов между "can" и "t", как в следующем примере:

can.*t

Онон будет соответствовать всем строкам.

Возможность соответствовать "нюлю или более" называется так же термином "включая". Расширенный набор спецсимволов используемый в egrep и awk предоставляет некоторые варианты включения, которые могут быть удобней. Знак плюс (+) соответствует одному или более вхождений перед регулярным выражением. Наш предыдущий пример для поиска одного или более пробелов может быть просто записан как:

+

Спецсимвол знак плюс может быть понят как "по крайней мере один" из предыдущих символов. Фактически, это лучше соответствует тому, как люди думают о работе звездочки.

Знак вопроса (?) соответствует нулю или одному вхождению. Для примера, в прошлом примере мы использовали регулярное выражение для поиска "80286", "80386"и "80486". Если мы захотим так же найти строку "8086", мы можем написать регулярное выражение, которое будет использовано в egrep или awk:

80[234]?86

Это соответстсвует строке "80", затем "2" или "3" или "4" или ни один из них, затем строка "86". Не перепутайти ? в регулярных выражениях и ? в подстановке в шелле. В шелле ? представляет одиночный символ, эквивалент . в регулярных выражениях.

3.2.6 Что такое Слово? Часть 1

Как Вы возможно догадались, иногда сложно найти полное слово. Для примера, если мы хотим найти соответствия шаблону "book", наш поиск вернет строки содержащие слово "book" и "books" и так же слова "bookish," "handbook," и "booky." Очевидно сделать ограничения вокруг "book" пробелами.

book

Как правило, это выражение будет соответствовать тлько слову "book"; и пропустит множественное число books". Для соответствия одиночному или множественному слову, Вам следует использовать спецсимвол звезддочка:

books*

Это соответствует "book" или "books". Как правило, он не найдет "book", если за ним идет точка, запятая, кавычка или знак вопроса.

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

book.*

Это выражение соответствует строке "book", за которой следует "любое количество символов или ни с пробелом". Вот несколько строк, которые подходят:

Here are the books that you requested

Yes, it is a good book for children

It is amazing to think that it was called a "harmful book" when

once you get to the end of the book, you can't believe

(Обратите внимание, что только вторая строка будет соответствовать фиксированной строке "book".) Выражение "book.*" соответствует так же строкам, содержащим такие слова, как booky", "bookworm" и "bookish". Нам следует убрать два из этих соответствий используя разные изменения. Знак вопроса (?), который является частью расширенного набора спецсимволов, соответствует 0 или 1 вхождению предыдущего символа. Таким образом, выражение:

book.?

будет соответствовать "book", "books" и "booky", но не "bookish" и "bookworm". Для исключения слов похожих на "booky, мы можем использовать класс символов, для указания всех символов на этом месте, которые мы хотим найти. Кроме того, поскольку спецсимвол знак вопроса не доступен в sed, мы должны будем прибегнуть к классам символов, как вы увидите позже.

Пытаться включить все не всегда практично, особенно когда используется grep. Иногда лучше оставить выражение простым и допустить упущения. Как правило, при использовании регулярного выражения в sed для замены, Вам следует быть более внимательным с результатом работы Вашего регулярного выражения. Мы более всесторонне рассмотрим регулярные выражения для поиска слов в части 2 "Какое слово?", позже в этой главе.

3.2.7 Позиционные спецсимволы.

Здесь два спецсимвола, которые позволят Вам указать контекст, в котором строка встречается, либо начало строки либо конец строки. Спецсимвол циркумфлекс (^) является одиночным символом регулряного выражения и обозначает начало строки. Спецсимвол знак доллар ($), тоже одиночный символ регулярного выражения и обозначает конец строки. Их часто называют "якоря", поскольку они ограничивают результат поиска в определенной позиции. Вы можете напечатать строки, начинающиеся с табуляции:

^

(Здесь показан обычный символ табуляции, который обычно не печатается. Без спецсимвола ^ , это выражение напечатает все строки содержащие табуляцию.

Обычно, используя vi для ввода текста, чтобы обработать его в troff, Вы не хотите видеть пробелы в конце строки. Если Вы хотите найти (и удалить) их, это регулярное выражение найдет строки с одним и более пробелами в конце строки.

*$

запросы и макросы troff вводятся в начале строки. Это двухсимвольные строки, с точкой впереди. Если запрос или макрос имеют аргумент, за ними следует пробел. Регулярное выражение используется для поиска таких запросов, как:

^\...

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

Вы можете использовать оба позиционных спецсимвола вместе, для поиска пустых строк:

^$

Вы можете использовать этот шаблон для подсчета количества пустых строк в файле, опция счетчика -с, для grep:

$ grep -c '^$' ch04

5

Это регулярное выражение удобное, если Вы хотите удалить пустые строки используя sed. Следующее регулярное выражение может быть использовано для поиска пустых строк, если даже они содержат пробелы:

^ *$

Кроме того, Вы можете найти всю строку:

^.*$

с которой вы возможно хотите что-то сделать с помощью sed.

В sed (и grep), "^" и "$" специальные только когда они встречаются в начале или конце регулярного выражения, соответственно. Таким образом, "^abc" означает "найти буквы a, b и c, только если они в начале строки" в то время как "ab^c" означает "найти a, b, символ ^и затем c, где угодно в строке". Это же справедливо и для "$".

В awk по другому, "^" и "$" всегда специальные, даже если они дают возможность написать выражение, которое не соответстсвует ничему. Выделяйте их для использования в awk, когда Вы хотите найти символы "^" или "$", следует их выделить с помощью бэкслеша, не важно в каком месте регулярного выражения они находятся.

3.2.7.1 Фразы

Программы с поиском по шаблону, такие как grep, не найдут результат, если он длинней двух строк. Для всех практических целей, трудно гарантированно найти фразу. Запомните, что текстовый файле, обычно не имеет структуры и строки обрываются абсолютно случайно. Если Вы ищите любую последовательность слов, возожмно они встретятся на одной строке, но они могут быть и разделены на две.

Вы можете написать серию регулярных выражений для нахождения фраз:

Almond Joy

Almond$

^Joy

Не очень хорошо, если воторое регулярное выражение найдет "Almond" в конце строке, вне зависимости начинается следующая строка с "Joy" или нет. Похожая проблема с третьим регулярным выражением.

Позже мы рассмотрим sed, и Вы изучите, как найти шаблон при множественных строках и Вы увидите шелл скрипт, включаютщий sed, который позволяет это делать.

3.2.8 Последовательность символов

Спецсимволы, позволяющием Вам указать повторяющиеся вхождения (*+?) показывают последовательность неограниченной длины. Разберем следующее выражение:

11*0

Онон будет соответствовать каждой из следующих строк:

10

110

111110

1111111111111111111111111110

Эти спецсимволы дают эластичность регулярному выражению.

Теперь давайте взглянем на пару спецсимволов, которые позволят Вам выявить последовательность и так же узнать ее длину . Итак, Вы можете указать максимальное и минимальное число вхождений символа или регулярного выражения.

\{ и \} доступна в grep и sed.[8] POSIX egrep bи POSIX awk используеют { и }. В любом случае, скобки включают один или два аргумента.

[8] Очень старые версии могут их не иметь; Будьте внимательны.

\{n,m\}

n и m числа между 0 и 255. Если Вы укажите одно \{n\}, тогда только n вхождений предшествующиего символа или регулярного выражения будут найдены. Если Вы укажите \{n,\}, тогда как минимум n вхождений будет найдено. Если Вы укажите \{n,m\}, тогда любое количество вхождений между n и m будет найдено.[9]

[9] Обратите внимание, что "?" эквиваленткно "\{0,1\}", а "*" эквивалентно "\{0,\}", а "+" эквивалентно "\{1,\}" и отсутствие изменений эквивалентно "\{1\}".

Для примера, следующее выражение соответствует "1001", "10001", и "100001", но не "101" or "1000001":

10\{2,4\}1

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

[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}

Аналогично, Северо Американский телефонный номер может быть описан следующим регулярным выражением:

[0-9]\{3\}-[0-9]\{4\}

Если Вы испольуете до-POSIX awk, у Вас не будет возможности использовать скобки, Вы можете просто повторить классы символов, соответствующий номер:

[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]

3.2.9 Альтернативные операции

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

UNIX|LINUX

найдет строки содержащие либо "UNIX" либо"LINUX". Может быть указано более одного варианта:

UNIX|LINUX|NETBSD

Строги, соответствующие любому из этих трех шаблонов будут напечатаны egrep.

В sed недостает спецсимвола объединения и Вам придется указывать каждый шаблон отдельно. В следующем разделе мы рассмотрим группирование операций, мы увидим дополнительные примеры этого спецсимвола.

3.2.10 Группирование операций

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

BigOne(Computer)?

Это выражение найдет строку отдельно строку "BigOne" или следующее одно вхождение "Computer". Аналогично, если термин был прописан и заменен на аббревиатуру:

$ egrep "Lab(oratorie)?s" mail.list

Bell Laboratories, Lucent Technologies

Bell Labs

Вы можете использовать скобкис совместно с вертикальной чертой для группировки операций. В следующем примере мы используем их для поиска единственного или множественного числа слова "company".

compan(y|ies)

Важно запомнить, что применение множества и помещения группы символов в скобки не возможно в большенстве версий sed и grep, но доступно во всех версиях egrep и awk.

3.2.11 Что такое Слово? Часть 2

Давайте пересмотрим регулярное выражение для поиска одиночного слова в свете новых спецсимволо, которые мы обсудили. Наша первая попытка написать регулярное выражение для grep, для поиска слова, включала следующее выражение:

book.*

Это выражение достаточно простое и ищет пробел, затем "book", затем любое количество символов и затем пробел. Как правило, как правило, оно не найдет все вхождения и найдет несколько неприятных слов.

Следующий тестовый файл содержит многочисленные вхождения "book". Мы добавили обозначения, которые не являются частью файла, для того, чтобы отличить входная строка должна быть найдена (>) и включена в вывод или отброшена (<). Мы постарались включить так много примеров, как это возможно.

$ cat bookwords

> This file tests for book in various places, such as

> book at the beginning of a line or

> at the end of a line book

> as well as the plural books and

< handbooks. Here are some

< phrases that use the word in different ways:

> "book of the year award"

> to look for a line with the word "book"

> A GREAT book!

> A great book? No.

> told them about (the books) until it

> Here are the books that you requested

> Yes, it is a good book for children

> amazing that it was called a "harmful book" when

> once you get to the end of the book, you can't believe

< A well-written regular expression should

< avoid matching unrelated words,

< such as booky (is that a word?)

< and bookish and

< bookworm and so on.

Так как ищем вхождения слова "book", то 13 строк должно быть найдено и 7 строк пропущено. Во-первых, давайте запустим предыдущее ругулярное выражение на тестовом файле и проверим результаты.

$ grep 'book.*' bookwords

This file tests for book in various places, such as

as well as the plural books and

A great book? No.

told them about (the books) until it

Here are the books that you requested

Yes, it is a good book for children

amazing that it was called a "harmful book" when

once you get to the end of the book, you can't believe

such as booky (is that a word?)

and bookish and

Оно напечатало только 8 из 13 строк которые мы хотели найти и напечатало 2 строки из тех, которые найти мы не хотели. Выражение ищет строки содержащие слова "booky"и "bookish". Оно игнорирует "book" в начале строки и в конце строки. Оно игнорирует слово "book", когда есть определенные знаки препинания.

Для ограничения поиска мы должны использовать классы символов. В общем, список символов, которые могут быть в конце слова, это следующие знаки пунктуации:

? . , ! ; : '

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

" () {} []

Вы также должны указать множественную или притяжательную форму слова.

Таким образом, Вы получите два разных сласса символов: до и после слова. Запомните, что все варианты из списка мы должны поместить в квадратные скобки. Перед словом мы имеем следующее:

["[{(]

и после слова:

[]})"?!.,;:'s]

Обратите внимание, помещая закрывающуюся квадратную скобку первым символом класса, мы делаем ее частью класса, до того, как закроем набор. Объединив два класса вместе, мы получим выражение:

["[{(]*book[]})"?!.,;:'s]*

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

$ grep " [\"[{(]*book[]})\"?!.,;:'s]* " bookwords

This file tests for book in various places, such as

as well as the plural books and

A great book? No.

told them about (the books) until it

Here are the books that you requested

Yes, it is a good book for children

amazing that it was called a "harmful book" when

once you get to the end of the book, you can't believe

Мы исключили строки, которые мы не хотели найти, но и не нашли четыре желаемых строки. Давайте рассмотрим четыре строки:

book at the beginning of a line or

at the end of a line book

"book of the year award"

A GREAT book!

Все эти проблемы вызваны расположением искомого слова в начале или конце строки. Так как нет пробела в начале или конце строки, шаблон не находится. Мы можем использовать спецсимволы указания позиции, ^ и $. Поскольку мы хотим найти пробел или начало или конец строки, мы можем использвать egrep и указать спецсимвол "или" внутри скобок для группировки. Для примера, для поиска начала строки илил пробела, Вы можете написать выражение:

(^| )

(Так как | и () являются часть расширенного набора спецсимволов, если Вы используете sed, то нужно написать другое выражение для получения этого результата.)

Вот пересмотренное регулярное выражение:

(^| )["[{(]*book[]})"?\!.,;:'s]*( |$)

Сейчас давайте посмотрим как оно работает:

$ egrep "(^| )[\"[{(]*book[]})\"?\!.,;:'s]*( |$)" bookwords

This file tests for book in various places, such as

book at the beginning of a line or

at the end of a line book

as well as the plural books and

"book of the year award"

to look for a line with the word "book"

A GREAT book!

A great book? No.

told them about (the books) until it

Here are the books that you requested

Yes, it is a good book for children

amazing that it was called a "harmful book" when

once you get to the end of the book, you can't believe

Это абсолютно полное регулярное выражение;как правило ,оно может быть разбито на части.Это выражение может не найти каждый одиночный пример, но оно может быть легко приспособлено для других вхождений, который Вы можете найти.

Можно также создать простой шелл скрипт для замены "book" на аргумент из командной строки. Единственная проблема, которая может возникнуть, это множественная форма слова, она не всегда "s.". Легким движением руки, можно добавить "es" множественное число, добавив "е" в класс символов следующих за словом; это будет работоспособно для большинства случаев.

Далее внимение, редакторы ex и vi имеют особые спецсимволы для поиска строки в начале слова \< и для поиска строки в конце слова \>. Используются они в паре, они могут найти строку, если она содержит полное слова. ( для этих операторов, слово- это строк из непробельных символов, окруженная пробелами, или начало или конец строки). Поиск слова такая общая задача, что эти спецсимволы будут широко использоваться, если они будут доступны для всех регулярных выражений.[10]

[10] GNU программы, такие как GNU версия awk, sed и grep, так же поддерживают \< и \>.

Программа для выполнения одиночных замен (A Program for Making Single Replacements)

The MKS Toolkit, входит в набор UNIX утилит для DOS от Mortice Kern Systems, Inc., содержит очень удобную программу, называемую gres (глобальное регулярное выражение замены). Как и grep, она ищет шаблон в файле; как правило, она позволяет указать замену для искомой строки. Эта программа, фактически, упрощенная весрия sed, и как sed, она печатает все строки, независимо была произведена замена или нет. Она не делает изменений в самом файле. Вы перенаправляете вывод программы в файл, если хотите сохранить изменения.

gres не является частью стандарта UNIX, но это отличный инструмент. Он может быть создан, используя простой шелл скрипт, который вызывает sed для выполнения задачи.

$ cat gres

if [ $# -lt "3" ]

then

echo Usage: gres pattern replacement file

exit 1

fi

pattern=$1

replacement=$2

if [ -f $3 ]

then

file=$3

else

echo $3 is not a file.

exit 1

fi

A="`echo | tr '\012' '\001' `" # See footnote[11]

sed -e "s$A$pattern$A$replacement$A" $file

В оставшейся части этой главы мы будем использовать gres для демонстрации использования спецсимволов замены. Запомните, что все, что применимо к gres, так же применимо и к sed. Сейчас мы заменим найденую строку с помощью ругулярного выражения "A.*Z" на двойной ноль (00).

$ gres "A.*Z" "00" sample

00ippy, our dog

00iggy

00elda

3.2.12 Ваша змена здесь

Когда Вы используете grep, редко будет важно, как Вы находите результат, пока Вы его находите. Когда Вы хотите произвести замену, как правило, Вы оцениваете результат поиска. Итак, какие символы строки в действительности находятся?

В этой части мы рассмотрим несколько примеров, которые демонстрируют степень совпадения. Тогда мы будем использовать программу, которая карботает как grep, но так же позволят указать заменяемую строку. В последствии, мы рассмотрим несоклько спецсимволов, используемых для описания строки замены.

3.2.12.1 Степень совпадения

Взглянем да следующее регулярное выражение:

A*Z

Это соответствует "ноль или более вхождений А, затем Z". Оно предоставит такой же результат, что и указание просто "Z". Буква "А" может быть, а может и нет; фактически, бука "Z" единственный искомый символ. Вот простой файл из двух строк:

All of us, including Zippy, our dog

Some of us, including Zippy, our dog

Если мы попробуем попробуем искать предыдущим регулярным выражение, то обе строки будут напечатаны. Любопытно что, оба совпадения произошли благодаря "Z" и только "Z". Мы можем использовать команду gres (см. врезку "Программа для одиночных замен") для демонстрации степени совпадения.

$ gres "A*Z" "00" test

All of us, including 00ippy, our dog

Some of us, including 00ippy, our dog

Мы ожидали сопадения в первой строки от "А" до "Z", но только "Z" подошло. Этот результат может быть очевидным, если мы немного изменим регулярное выражение:

A.*Z

".*" интерпретируется как "ноль или более вхождений любых символов", что означает "любое количество символов" может быть найдено, в том числе никакие. Полностью выражение может быть оценено как "полсе А следует любое количество символов, затем Z". "А" будет первым символом в шаблоне и "Z" будет последним; все, что угодно или ничего может быть между. Запуск grep на этом же двухстрочном файле выведет одну строку. Мы добавили строку с каретками (^) снизу, чтобы отметить, что было найдено.

All of us, including Zippy, our dog

^^^^^^^^^^^^^^^^^^^^^^

Степень совпадения от "A" до "Z". Такое регулярное выражение будет соответствовать и следующей строке:

I heard it on radio station WVAZ 1060.

^^

Строка "A.*Z" соответствует "А, затем любое количество символов(включая ноль), затем Z". Сейчас, давайте взглянем на похожий набор простых строк, которые содержат множественные вхождения "A" и "Z".

All of us, including Zippy, our dog

All of us, including Zippy and Ziggy

All of us, including Zippy and Ziggy and Zelda

Регулярное выражение "A.*Z" найдет наиболее длинную строку в каждом случае.

All of us, including Zippy, our dog

^^^^^^^^^^^^^^^^^^^^^^

All of us, including Zippy and Ziggy

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

All of us, including Zippy and Ziggy and Zelda

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Это может быть проблемой, если Вы хотите найти наиболее короткий возможный вариант.

3.2.13 Ограничение степени совпадения

Раньше мы говорили, что ругулярное выражение старается найти наиболее длинную возможную строку и это может вызавать неожиданные проблемы. Для примера, посмотрим на регулярное выражение для поиска любого количества символов внутри кавычек:

".*"

Давайте посмотрим на troff, который имеет два аргумента в кавычках ,как показано ниже:

.Se "Appendix" "Full Program Listings"

для поиска первого аргумента, мы можем описать шаблон следующим ругулярным выражением:

\.Se ".*"

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

\.Se ".*" ".*"

Кроме того, это работает как и ожидается, каждая строка может не иметь такое количество аргументов, что вызовет исключения - Вам просто нужен первый аргумент. Вот другое регулярное выражение, которое ищет наиболее короткое совпадение между двумя кавычками:

"[^"]*"

Это соответствует "за кавычкой следует любое количество символов, кроме кавычки и затем следует кавычка":

$ gres '"[^"]*"' '00' sampleLine

.Se 00 "Appendix"

А сейчас, давайте рассмотрим несколько строк с символом точка (.), используемой для разделения чисел на два столбца:

1........5

5........10

10.......20

100......200

Сложность в поиске символа разделения в том, что их число меняется. Давайте скажем, что нужно заменить все разделители на одиночную табуляцию. Вы можете написать регулярное выражение для поиска строки следующим:

[0-9][0-9]*\.\.*[0-9][0-9]*

Это выражение может неожиданное найти строку:

see Section 2.3

Ограничим совпадение, указав минимальное количество точек, общее для всех строк:

[0-9][0-9]*\.\{5,\}[0-9][0-9]*

Это выражение использует квадратные скобки в sed для поиска "цифра, затем по крайней мере пять точке и затем цифра". Чтобы увидеть это в действии, мы покажем команду sed, которая замени точки на дефис. Обычно, мы не скрываем синтаксис спецсимволов замены в sed - \( и \) для сохраниния части регулярного выражения и \1 и \2 для восстановления сохраненной позичии. Эта команда может выглядеть довольно полной(так и есть!) но она выполняет сови задачи.

$ sed 's/\([0-9][0-9]*\)\.\{5,\}\([0-9][0-9]*\)/\1-\2/' sample

1-5

5-10

10-20

100-200

Аналогичное выражение может быть написсано для поиска одного и более разделителей или табуляций между столбцами данных. Можно изменить порядок столбцов, так же как поменять табуляцию на любой другой разделитель. Вам следует поэксперементировать самостоятельно, делая простые и полные замены, используя sed или gres.

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется

Переведено на Нотабеноиде
http://notabenoid.org/book/32181/117179

Переводчики: r0mk

Настройки

Готово:

100.00% КП = 1.0