Руководство пользователя для GNU Awk

Arnold D. Robbins
перевод Балуева А. Н.

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

Оглавление

В начало страницы

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

Регулярное выражение, заключенное в слеши (`/') представляет awk-образец, который соответствует входным записям, тексты которых принадлежат упомянутому множеству.

Простейшее регулярное выражение есть последовательность букв, цифр или и тех и других. Такое regexp соответствует каждой цепочке, содержащей эту последовательность. Так, regexp `foo' соответствует всякой цепочке, содержащей `foo'. Поэтому образец /foo/ соответствует всякой входной записи, содержащей тройку символов `foo' где-либо в записи. Другие виды regexp позволяют указывать более сложные классы цепочек.

Вначале примеры будут простыми. Когда мы объясним точнее работу регулярных выражений, мы приведем более сложные примеры.

4.1 Как использовать регулярные выражения

В начало страницы

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

$ awk '/foo/ - print $2 ""' BBS-list

a 555-1234 a 555-6699 a 555-6480 a 555-2127

Регулярные выражения могут также использоваться в выражениях соответствия. Эти выражения позволяют вам указывать цепочки, которым они соответствуют; Это не обязательно целая текущая входная запись. Два оператора, `~' и `!~', производят сравнение регулярных выражений. Выражения с этими операциями могут использоваться в качестве образцов или в составе операторов if, while, for и do.

exp ~ /regexp/

имеет значение true, если выражение exp (рассматриваемое как цепочка) соответствует regexp.

Следующий пример соответствует (то есть выбирает) все входные записи, имеющие букву верхнего регистра `J' в любой позиции в первом поле:

$ awk '$1 ~ /J/' inventory-shipped

a Jan 13 25 15 115 
a Jun 31 42 75 492 
a Jul 24 34 67 436 
a Jan 21 36 64 620

То же самое делает программа:

awk '- if ($1 ~ /J/) print ""' inventory-shipped

Выражение exp !~ /regexp/ имеет значение true, если выражение exp (рассматриваемое как цепочка символов) не соответствует regexp. Следующий пример отбирает все входные записи, в которых первое поле не содержит букву верхнего регистра `J':

$ awk '$1 !~ /J/' inventory-shipped

a Feb 15 32 24 226 
a Mar 15 24 34 228 
a Apr 31 52 63 420 
a May 16 34 29 208...

Когда regexp заключено в слеши, подобно /foo/, мы называем его константой regexp, подобно численной константе 5.27, а "foo" есть строковая константа.

4.2 Управляющие последовательности

В начало страницы

Некоторые символы не могут быть включены прямо в строковые константы ("foo") или константы regexp (/foo/). Вместо этого они представляются с помощью управляющих последовательностей, которые являются символьными последовательностями, начинающимися с обратного слеш (`"'). Одно из назначений управляющих последовательностей --- включать знак двойной кавычки в строковую константу. Поскольку просто двойная кавычка оканчивает цепочку, нужно употреблять `""' для представления символа двойной кавычки как члена цепочки.

Например:

$ awk 'BEGIN - print "He said ""hi!"" to her." ""'

a He said "hi!" to her.

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

Другая роль обратного слеш состоит в представлении непечатных символов, таких как tab или newline. Хотя ничего не препятствует вам вставлять большинство непечатных символов в строковую константу или константу regexp, они могут выглядеть странно.

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


"" обратный слеш, `"'.
"a  Символ "внимание", Control-g, ASCII code 7 (BEL).
"b Backspace, Control-h, ASCII code 8 (BS).
"f Formfeed, Control-l, ASCII code 12 (FF).
"n Newline, Control-j, ASCII code 10 (LF).
"r Carriage return, Control-m, ASCII code 13 (CR).
"t Horizontal tab, Control-i, ASCII code 9 (HT).
"v Vertical tab, Control-k, ASCII code 11 (VT).
"nnn Восьмеричное значение  nnn, 

где nnn есть одна-три цифры между `0' и `7'.

 Например, код для  ASCII ESC (escape) символа есть  `"033'.
 
"xhh... Шестнадцатеричное значение hh, 

где  hh есть шестнадцатеричные цифры

  (от `0' до  `9' и от  `A' до  `F' или от `a' до  `f').

Подобно аналогичным конструкциям в ANSI C, управляющие последовательности продолжаются, пока не достигается первый не-шестнадцатеричный символ. Однако, употребление больше чем двух шестнадцатеричных цифр приводит к неопределенному результату. ( `"x' управляющая последовательность недопустима в POSIX awk.)

"/ Слеш (необходим только в константах regexp). Используется, если вы хотите написать regexp-константу, содержащую слеш. Поскольку regexp ограничивается слешем, вы должны отметить слеш как часть образца, чтобы побудить awk продолжать обработку regexp.

"" Двойная кавычка (необходима только для строковых констант). В gawk имеются еще две символьные последовательности, которые начинаются с обратного слеш и имеют специальное значение в regexp. См. раздел 4.4 [Дополнительные операторы в Regexp, только для gawk], стр. 31.

Что произойдет, если вы поместите в строчной константе обратный слеш перед тем, что не является одним из символов, перечисленных выше? В POSIX awk это не определено намеренно. Имеются две возможности:

1. Вычеркнуть обратный слеш. Это делают оба Unix awk и gawk. Например, "a"qc" то же самое что "aqc".

2. Оставить обратный слеш в одиночестве. Некоторые другие реализации awk делают это. В такой реализации "a"qc" есть то же самое как напечатать "a""qc".

В regexp обратный слеш перед любым символом, который отсутствует в предыдущей таблице и не указан в разделе 4.4 [Дополнительные Regexp операторы, только для gawk], стр. 31, означает, что следующий символ должен быть воспринят буквально, даже если это есть орератор regexp.

 Например,

 /a"+b/ соответствует трем символам
 `a+b'.

Для полной переносимости не употребляйте обратный слеш перед символами, не перечисленными в таблице, приведенной выше.

Возникает еще один интересный вопрос. Предположим, вы используете восьмеричную или шестнадцатеричную управляющие последовательности для представления некоторого метасимвола в regexp (см. раздел 4.3 [Операторы в регулярных выражениях], стр. 26). Должен ли awk рассматривать этот символ буквально или как оператор в в regexp? Оказывается, что исторически такие символы рассматривались буквально (d.c.). Однако, стандарт POSIX указывает, что они должны рассматриваться как настоящие метасимволы, и gawk как раз это и делает. Вместе с тем в режиме эмуляции (см. раздел 14.1 [Параметры командной строки], стр. 161), gawk трактует символы, представленные восьмеричными или шестнадцатеричными управляющими последовательностями буквально, если они употреблены в константах regexp.

Так, /a"52b/ эквивалентно  /a"*b/.

Подведем итоги:

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

2. gawk обрабатывает константы regexp и динамические regexp (см.раздел 4.7 [Использование динамических regexp], стр. 35) для специальных операторов, перечисленных в разделе 4.4 [Дополнительные операторы Regexp, только в gawk], стр. 31.

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

4.3 Операторы регулярных выражений

В начало страницы

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

Управляющие последовательности, описанные выше, в разделе 4.2 [Управляющие последовательности], стр. 24, действуют внутри regexp. Они вводятся с помощью `"'. Они распознаются и конвертируются в соответствующие реальные символы на самом первом шаге обработки regexp.

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

"  используется для уничтожения специального значения символа при установке
соответствия. 

Например,  "$ означает символ `$'.

^ соответствует началу цепочки. Например, ^@chapter соответствует `@chapter' в начале цепочки и может использоваться для идентификации начала главы в исходных файлах Texinfo. `^' называется якорем, поскольку он побуждает образец сравниваться только с началом цепочки. Важно знать, что якорь `^' не соответствует началу строки, вложенной в цепочку.

В следующем примере условие не выполнено:

if ("line1"nLINE 2" ~ /^L/) ...

$ аналогично `^', но отмечает только конец цепочки. Например, p$ соответствует записи, которая оканчивается на `p'. `$' тоже якорь и тоже не означает конец строки, вложенной в цепочку.

В следующем примере условие имеет значение ложь:

if ("line1"nLINE 2" ~ /1$/) ...

. точка соответствует любому одиночному символу, включая символ newline. Например, .P соответствует любому одиночному символу, предшествующему в цепочке букве `P'.

Использую конкатенацию, мы можем строить регулярные выражения по примеру `U.A', представляющему любую трехсимвольную последовательность, начинающуюся с `U' и кончающуюся на `A'. В строгом режиме POSIX (см. раздел 14.1 [Параметры командной строки], стр. 161), `.' не соответствует пустому символу, все биты которого равны 0. В остальных случаях пустой символ рассматривается как обычный символ. Другие версии awk не могут обнаруживать пустой символ.

[...] называется списком символов. Он соответствует любому из символов, заключенных в квадратные скобки. Например, [MVX] соответствует любой из букв `M', `V' или `X' в цепочке. Диапазоны символов указываются с помощью дефиса между начальным и конечным символами и заключением всего выражения в квадратные скобки. Например, [0-9] означает любую цифру. Допустимы и кратные диапазоны. Например, список [A-Za-z0-9] есть обычный способ указания всех латинских букв и цифр.

Чтобы включить один из символов `"', `]', `-' или `^' в список символов, поставьте перед ним `"'.


Например:

 [d"]] означает  `d' или  `]'. 
 
 

Такое использование `"' в списке символов совместимо с другими реализациями awk и допускается в POSIX. Регулярные выражения в awk образуют супермножество спецификаций POSIX для Расширенных Регулярных Выражений (EREs). POSIX EREs основаны на регулярных выражениях, принятых в традиционных утилитах l egrep. Классы символов представляют новую черту, введенную в стандарт POSIX. Символьный класс есть специальное обозначение для описания списков символов, имеющих специальные атрибуты, но где сами фактические символы могут меняться от страны к стране и/или от одного символьного множества к другому. Например, понятие буквенного символа в США отличается от того же во Франции.

Символьный класс имеет смысл только в внутри скобок символьного списка. Символьный класс состоит из `[:', ключевого слова класса, и `:]'.

Приведем символьные классы, определенные в стандарте  POSIX.

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

[:alpha:]      Буквенные символы.

[:blank:]      Пробелы и знаки табуляции.

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

[:digit:]      Цифры.

[:graph:]      Символы, которые и печатны и одновременно видимы. (Пробел
               печатный, но невидимый, а `a' печатен и видим.)

[:lower:]      Буквы нижнего регистра.

[:print:]      Печатные символы (символы, не являющиеся управляющими.)

[:punct:]      Знаки пунктуации (не буквы, цифры, управляющие или пробелы.)

[:space:]      Знаки пробелов (пробел, tab, formfeed).

[:upper:]      Буквы верхнего регистра.

[:xdigit:]     Шестнадцатеричные цифры.

Например, до стандарта POSIX, для выделения букв и цифр нужно было писать /[A-Za-z0-9]/. Если ваше множество содержит и другие буквы, они не будут обнаружены. С помощью классов POSIX можно писать /[[:alnum:]]/, что будет отвечать всем буквам и цифрам вашего символьного множества.

Две дополнительные специальные последовательности могут фигурировать в символьных списках. Они относятся к не-ASCII символьным множествам, которые могут иметь отдельные символы (называемые упорядочивающими элементами), представляемые более чем одним символом, или группы символов, которые равнозначно используются в целях упорядочивания или сортировки. (Например, во Франции простое "e" и имеющее аксант-граф "`e" эквивалентны.)

Сортирующие символы (Collating Symbols) Сортирующий символ есть многосимвольный упорядочивающий элемент, заключенный в `[.' и `.]'. Например, если `ch' есть упорядочивающий элемент, то [[.ch.]] есть regexp, которое соответствует этому упорядочивающему элементу, в то время как [ch] есть regexp, которое соответствует либо `c' либо `h'.

Классы эквивалентности

В начало страницы

Класс эквивалентности есть региональное специальное имя для списка символов, которые эквивалентны. Это имя заключается в `[=' и `=]'. Например, имя `e' может использоваться для представления всех "e," "`e," и "'e." В таком случае [[=e]] есть regexp, соответствующий любому из `e', `'e', или ``e'. Эти черты очень ценны в не англоязычных регионах.

Внимание: библиотечные функции, которые gawk использует для регулярных выражений, соответствуют только признанным в POSIX классам символов; они не распознают упорядочивающих символов или классов эквивалентности. [^ ...] есть дополнение к списку символов (первый символ после `[' должен быть`^'). Оно соответствует любым символам кроме тех, которые находятся в квадратных скобках.

Например, 

	[^0-9]	соответствует любому символу, кроме цифр.

	--  	представляет оператор альтернативы и 
		 используется для указания альтернатив.
		  
Например,

   ^P--[0-9]  соответствует любой цепочке, 
		которая соответствует либо
					  
`^P' либо `[0-9]'.
		    То есть это соответствует всякой цепочке,
 		    которая начинается с `P' или содержит цифру.

Альтернатива связывает наибольшие возможные regexp с обеих сторон. Другими словами, `--' имеет наинизший приоритет среди всех операторов над регулярными выражениями.

Скобки (...) используются для группировок в регулярных выражениях, как и в арифметических. Они могут использоваться для конкатенации регулярных выражений, содержащих оператор альтернативы `--'. Например, `@(samp--code)"-[^""]+"""' соответствует как `@code-foo""' так и `@samp-bar""'. (Они являются форматирующими управляющими последовательностями для Texinfo.)

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

Например, ph* означает применение символа `*' к предшествующему `h' и соответствует `p' с следующими за ним любым количеством `h' ( в том числе и нулевым, то есть одному `p'). `*' повторяет наименьшее возможное предшествующее выражение (используйте скобки, если нужно повторить большее выражение) любое количество раз.

Например,

awk '/"(c[ad][ad]*r x")/ - print ""' sample

печатает каждую запись из `sample', 
содержащую цепочку вида

`(car x)', `(cdr x)', `(cadr x)', и т. д. 

Заметьте исключение скобок посредством 
предварения их обратными слешами.

+ Этот символ действует подобно `*', но предшествующее выражение должно быть повторено по крайней мере один раз. Это значит, что wh+y соответствует `why' и `whhy', но не `wy', в то время как `wh*y' соответствует всем трем приведенным цепочкам.

Вот более простой способ записи последнего примера
на `*' :

awk '/"(c[ad]+r x")/ - print ""' sample

? Этот символ также действует подобно `*', но предшествующее выражение повторяется или раз или ни разу. Например, fe?d соответствует `fed' и `fd', и ничему другому.

-n"" -n,"" -n,m"" Одно или два числа внутри фигурных скобок означают интервальное выражение. Если в фигурных скобках стоит одно число, предшествующее regexp повторяется n раз. Если там два числа, разделенные запятой, то предшествующее regexp должно повторяться от n до m раз. Если имеется одно число с последующей запятой, то предшествующее regexp должно повторяться не меньше чем n раз.

wh-3""y соответствует `whhhy', но не `why' или `whhhhy'. wh-3,5""y соответствует только `whhhy' или `whhhhy' или `whhhhhy'. wh-2,""y соответствует `whhy' или `whhhy', и т.д.

Интервальные выражения традиционно не использовались в awk. Как часть стандарта POSIX, они добавлены, чтобы сделать awk и egrep совместимыми друг с другом.

Однако, поскольку старые программы могут использовать `-' и `""' в константах regexp constants, по умолчанию gawk не обрабатывает интервальные выражения в regexp. Если указаны либо `--posix' либо `--re-interval' (см. раздел 14.1 [Параметры командной строки], стр. 161), то интервальные выражения допускаются в regexp.

В регулярных выражениях операторы `*', `+' и `?', также как и фигурные скобки `-' and `""', имеют наивысший приоритет, затем идет конкатенация и, наконец, `--'. Как и в арифметике, круглые скобки могут изменить порядок действий.

Если gawk дейсвует в режиме эмуляции (см. раздел 14.1 [Параметры командной строки], стр. 161), классы символов и интервальные выражения недопустимы в регулярных выражениях.

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

4.4 Дополнительные Regexp-Операторы, только для gawk

В начало страницы

Программное обеспечение GNU при обработке регулярных выражений допускает некоторое количество дополнительных операторов. Эти операторы описаны в настоящем разделе. Они специфичны для gawk и не могут использоваться в других реализациях awk.

Большинство дополнительных операторов предназначены для установки соответствий между словами. В нашем случае слово есть последовательность из одной или более букв, цифр или символов подчеркивания (`.').

"w оператор соответствует любому символу из состава слова, т.е. букве, цифре или подчеркиванию. Его можно мыслить как сокращение для [[:alnum:].].

"W означает любой символ кроме образующих слово. Он может мыслиться как сокращение для [^[:alnum:].].

"! оператор означает пустую цепочку в начале слова. Например, /"!away/ соответствует `away', но не `stowaway'.

"? оператор соответствует пустой цепочке в конце слова. Например, /stow"?/ соответствует `stow', но не `stowaway'.

оператор соответствует пустой цепочке или в начале или в конце слова (на границе слова). Например, `"yballs?"y' соответствует или `ball' или `balls' как отдельным словам.

"B оператор отвечает пустой цепочке в пределах слова. Другими словами, `"B' соответствует пустой цепочке, которая находится между двумя входящими в состав слова символами. Например, /"Brat"B/ соответствует `crate', но не соответствует `dirty rat'. `"B' есть существенная противоположность `"y'.

Имеются еще два оператора, которые действуют на буферах. В Emacs буфер, естественно, есть буфер Emacs. Для других программ подпрограммы из библиотеки подпрограмм для regexp, которые использует gawk, рассматривают всю цепочку для соответствия как буфер.

Для awk, поскольку `^' и `$' всегда действуют в терминах начала и конца цепочек, эти операторы не прибавляют никаких новых возможностей. Они добавлены только для совместимости с другими программами обеспечения GNU.


"` Этот оператор соответствует пустой строке в начале буфера.

"' Этот оператор соответствует пустой строке в конце буфера.

В других программных обеспечениях GNU оператор границ слов есть `"b'. Однако, это противоречит с определением в языке awk `"b' как возврата на одну позицию (backspace), поэтому в gawk используется другая буква.

Альтернативным методом могло бы быть требование двух обратных слешей в операторах GNU, но это было сочтено слишком запутанным, и текущий способ употребления `"y' вместо `"b' в GNU кажется меньшим из двух зол.

Различные параметры командной строки (см. раздел 14.1 [Параметры командной строки], стр. 161) управляют интерпретацией gawk символов в regexp. По умолчанию gawk обеспечивает все средства операторов в POSIX regexp и GNU regexp, описанные выше. Однако, интервальные выражения не обрабатываются.

Далее перечисляются возможные параметры и их  действие.

--posix

Обрабатываются только POSIX regexp, операторы GNU не рассматриваются (например, `"w' соответствует литералу `w'). Интервальные выражения допускаются.

--traditional

Соответствие традиционным Unix awk regexp. Операторы GNU не должны быть специальными, интервальные выражения не используются, не допускаются символьные классы POSIX ([[:alnum:]] и т.д.). Символы в восьмеричных и шестнадцатеричных управляющих последовательностях рассматриваются буквально, даже если последовательности представляют метасимволы regexp.

--re-interval

Допускаются интервальные выражения в regexp, даже если `--traditional' был ранее указан.

4.5 Зависимость от регистра при определении соответствия

В начало страницы

Нормально регистр учитывается в регулярных выражениях при соответствии простых символов (т.е. не метасимволов) и внутри символьных множеств. Так, `w' в регулярном выражении соответствует только `w' нижнего регистра и не соответствует верхнерегистровому `W'.

Простейший путь для независимого от регистра соответствия есть использование символьного списка: `[Ww]'. Однако, это может оказаться громоздким, если это нужно часто; и это может затруднить прочтение регулярного выражения. Имеются две альтернативы для упрощения.

Один путь устроить нечувствительное к регистру соответствие в некоторой точке программы есть конвертирование данных к одному регистру с помощью встроенных функций tolower или toupper (их мы еще не рассматривали; см. раздел 12.3 [Встроенные функции для действий с цепочками], стр. 137). например, tolower($1) ~ /foo/ - ... "" переводит первое поле в нижний регистр перед проверкой соответствия с ним. Это работает в любой реализации awk, соответствующей POSIX.

Другой метод, специальный для gawk, состоит в установке переменной IGNORECASE на ненулевое значение (см. Главу 10 [Встроенные переменные], стр. 115). Когда IGNORECASE не равна нулю, все операции над regexp и цепочками игнорируют регистр. Изменяя динамически значение IGNORECASE, можно управлять чувствительностью к регистру во время исполнения программы. По умолчанию регистр учитывается, потому что IGNORECASE (подобно большинству переменных) инициализируется нулем.


x = "aB" if (x ~ /ab/) ... # этот тест не сработает

IGNORECASE = 1 if (x ~ /ab/) ... # теперь пройдет успешно

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

IGNORECASE может быть установлена из командной строки или правилом BEGIN (см. раздел 14.2 [Остальные аргументы командной строки ], стр. 165; также см. раздел 8.1.5.1 [Действия при запуске и очистке], стр. 100). Установка IGNORECASE из командной строки есть способ сделать программу чувствительной к регистру без редактирования ее.

До версии 3.0 gawk значение IGNORECASE влияло только на операции regexp. Оно не действовало на сравнение цепочек по `==', `!=', и т.д. Начиная с версии 3.0, как regexp операции, так и операции сравнения цепочек подчинены значениям IGNORECASE.

Начиная с версии gawk 3.0, эквивалентность символов верхнего и нижнего регистров относится к множеству символов ISO-8859-1 (ISO Latin-1). Это множество есть супермножество традиционных символов 128 ASCII, которое также содержит некоторое количество символов, используемых в европейских языках.

Значение IGNORECASE безразлично, если gawk действует в режиме эмуляции (см. раздел 14.1 [Параметры командной строки], стр. 161). Регистр всегда учитывается в режиме эмуляции.

4.6 Как много текста учитывается при определении соответствия?

В начало страницы
Рассмотрим следующий пример:

echo aaaabcd -- awk '- sub(/a+/, "!A?"); print ""'

В нем используется функция sub (которую мы еще не обсуждали, см. раздел 12.3 [Встроенные функции для действий с цепочками], стр. 137) для изменения входной записи. Здесь regexp /a+/ означает "один или больше символов `a' " а замещающий текст есть `!A?'.

Ввод содержит четыре символа `a'. Каков будет результат? Другими словами, сколько "один или больше" будет учитывать awk, два, три или все четыре `a' ?

Ответ таков. Регулярные выражения в awk (и POSIX) всегда учитывают самую левую и самую длинную цепочку входных символов для соответствия. Поэтому в нашем примере все четыре символа `a' заменяются на `!A?'.


$ echo aaaabcd -- awk '- sub(/a+/, "!A?"); print ""'

a !A?bcd

Для простых тестов соответствует/не соответствует это не так важно. Но при обработке полей и расщеплении записей, при определении соответствия текстов и подстановок с помощью функций match, sub, gsub и gensub это очень важно. Понимание этого принципа также важно для опирающихся на regexp записей и разделения полей (см. раздел 5.1 [Как вход разделяется на записи], стр. 37, а также раздел 5.5 [Указание того, как разделяются поля], стр. 44).

4.7 Использование динамических регулярных выражений

В начало страницы

Правая сторона в операторах `~' или`!~' не обязана быть константой regexp (т.е. цепочкой символов между слешами). Это может быть любое выражение. Выражение вычисляется и превращается, если нужно, в цепочку; содержимое цепочек используется как regexp. Каждое regexp, которое вычисляется таким образом, называется динамическим regexp.


Например:

BEGIN - identifier.regexp = "[A-Za-z.][A-Za-z.0-9]+"
"" $0 ~ identifier.regexp - print ""

присваивает идентификатору identifier.regexp значение regexp, которое описывает имена переменных awk и проверяет, соответствует ли входная запись этому regexp.

Внимание: при употреблении операторов `~' и `!~' нужно различать константы regexp, заключенные в слеши, и константы-цепочки в двойных кавычках.

Если вы используете константы-цепочки, вы должны отдавать себе отчет в том, что цепочки сканируются дважды; первый раз, когда awk читает программу, и второй раз, когда awk ищет соответствие между цепочкой в левой части оператора to match the string on the с образцом справа. Так происходит с каждым выражением, имеющем значением цепочку (таким как identifier.reggexp в примере), не являющимся просто цепочкой-константой.

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

Например, /"*/ есть константа regexp для литерала `*'.

Нужен только один обратный слеш. Чтобы сделать то же самое с цепочкой, нужно напечатать """*". Первый обратный слеш управляет вторым, так что цепочка фактически содержит два символа `"' и `*'. Зная, что вы можете использовать и regexp и строковую константы для описания регулярного выражения, чем вы должны воспользоваться? Ответ будет: "постоянная regexp" в силу трех причин.

1. Константу -цепочку (или строковую константу) труднее писать и труднее читать. Использование константы regexp делает вашу программу более надежной. Непонимание разницы между двумя видами констант есть частый источник ошибок.

2. Употребление констант regexp делает программу эффективнее: awk может заметить, что вы употребили regexp и запомнить его в форме, более удобной для сравнения с образцом. Используя строковую константу, awk должен сначала перевести цепочку в внутреннюю форму, а затем произвести сравнение с образцом.

3. Употребление констант regexp --- предпочтительный стиль; он показывает ясно, что вы устанавливать соответствие с regexp.

В начало страницы

<<< Оглавление Страницы: 4  5 >>>