ОПИСАНИЕ
Регулярные выражения (РВ) стандарта POSIX.2 могут быть двух видов: новые РВ
(по сути, использующиеся в egrep; в POSIX.2 их называют ещё
«расширенными» РВ) и устаревшие РВ (по сути, использующиеся в ed(1); в
POSIX.2 их называют ещё «основными» РВ). Устаревшие РВ существуют, в
основном, для совместимости с некоторыми старыми программами (они будут
подробнее рассмотрены в конце этого документа). В POSIX.2 не разъяснены
некоторые вопросы синтаксиса РВ; знаком (!) отмечаются описания, которые
могут быть не полностью совместимы с другими реализациями POSIX.2.
Новое РВ — одна(!) или более непустых(!) ветвей, разделённых '|'. Соответствием считается, если есть совпадение для любой из её ветвей.
Ветвь состоит из одной(!) или более частей. Ветвь сначала ведёт поиск соответствий с первой, затем с второй (и т. п.) её частями.
Часть — это атом, за которым может следовать одиночный(!) символ '*', '+', '?' или интервал. Если за атомом следует символ '*', это означает, что совпадающая с атомом последовательность может встречаться 0 или более раз. Если за атомом следует символ '+', это означает, что совпадающая с атомом последовательность может встречаться 1 или более раз. Если за атомом следует символ '?', это означает, что совпадающая с атомом последовательность может встречаться 0 или 1 раз.
Интервал — это символ '{', после которого стоит беззнаковое целое десятичное число, за которым может следовать символ ',', далее, возможно, находится ещё одно беззнаковое целое десятичное число, и в конце интервала обязательно стоит символ '}'. Числа должны находиться в промежутке от 0 до RE_DUP_MAX (255(!)) включительно, а если указано два числа, то первое не должно превышать второе. Атом с интервалом, в котором есть одно число i и нет запятой, соответствует последовательности, повторяющейся точно i раз. Атом с интервалом, содержащим число i и запятую, соответствует последовательности, повторяющейся i и более раз. Атом с интервалом, содержащим два числа i и j, соответствует последовательности, повторяющейся от i до j раз включительно.
Атом — это регулярное выражение, заключённое в «()» (соответствующее регулярному выражению), пустые скобки «()» (соответствуют строке null)(!), выражение в квадратных скобках (см. ниже), '.' (соответствует любому одному символу), '^' (соответствует строке null в начале строки), '$' (соответствует строке null в конце строки), '\' со следующим после него одним из символов «^.[$()|*+?{\» (соответствует этому символу, как он есть), символ '\' с последующим символом, отличным от предыдущего(!) (соответствует этому символу, как он есть, как если бы '\' отсутствовал(!)), или одиночный символ без специального назначения (соответствует этому символу). Символ '{' с последующим символом, не являющимся цифрой, соответствует символу, а не началу интервала(!). Нельзя заканчивать РВ символом '\'.
Выражение в квадратных скобках — список символов, заключенный в «[]». Обычно, оно соответствует любому отдельному символу из списка (но см. ниже). Если список начинается с '^', то он соответствует любому отдельному символу (но см. ниже) не из приведённого списка. Если два символа в списке разделены '-', то это считается сокращением полного диапазона символов, заключённого между этими двумя символами (включая и их) объединяющей последовательности, например, «[0-9]» в кодах ASCII соответствует любой десятичной цифре. Нельзя(!) в двух диапазонах указывать один и тот же символ, например, «a-c-e». Диапазоны сильно зависят от объединяющей последовательности, и в переносимых программах их лучше не использовать.
Для того, чтобы включить в список символ ']', вам следует поставить его в начало списка (после символа '^', если он присутствует). Для того, чтобы включить в список символ '-', поставьте его первым или последним символом или вторым символом конца диапазона. Для того, чтобы обозначить символом '-' начало диапазона, заключите его в «[.» и «.]», сделав его объединяющим элементом (смотрите далее). За исключением этих и некоторых других комбинаций, использующих '[' (см. следующие параграфы), все остальные специальные символы, включая '\', теряют своё особое назначение в квадратных скобках.
Если внутри квадратных скобок объединяющий элемент (одиночный символ, многосимвольная последовательность, которая действует как одиночный символ или имя объединяющей последовательности) заключен в «[.» и «.]», то он обозначает последовательность символов как один объединяющий элемент. Последовательность выражается одиночным элементом списка внутри квадратных скобок. Таким образом, выражение в скобках, содержащее многосимвольный объединяющий элемент, может соответствовать более чем одному символу; например, если последовательность содержит объединяющий элемент «ch», то РВ «[[.ch.]]*c» соответствует первым пяти символам «chchcc».
Объединяющий элемент в квадратных скобках, заключенный в «[=» и «=]» — это класс-эквивалент, делающий последовательности символов всех объединяющих элементов эквивалентными одной, включая её саму (если нет больше эквивалентных объединяющих элементов, то это аналогично выражению, заключенному в «[.» и «.]»). Например, если o и являются членами класса-эквивалента, то «[[=o=]]», «[[==]]» и «[o]» являются синонимами. Класс-эквивалент не(!) может служить границей диапазона.
В выражении в квадратных скобках, имя символьного класса, заключенное в «[:» и «:]», соответствует списку всех символов, принадлежащих этому классу. Существуют стандартные символьные классы:
alnum digit punct
alpha graph space
blank lower upper
cntrl print xdigit
Эти символьные классы определены в wctype(3). В локали могут быть определены свои классы. Символьный класс не может использоваться в качестве границы диапазона.
В случае, если РВ совпадает более чем с одной подстрокой заданной строки, то оно считается совпадающим с первой подстрокой строки. Если РВ совпадает более чем с одной подстрокой начинающейся в этой точке, то оно совпадет с самой длинной подстрокой. Подвыражения также соответствуют самой длинной совпадающей подстроке, полное соответствие должно быть наиболее длинным, и подвыражения, стоящие в РВ первыми, имеют приоритет над остальными, находящимися далее. Заметим, что высокоуровневые подвыражения имеют приоритет над низкоуровневыми компонентами подвыражений.
Длина совпадений измеряется в символах, а не в объединяющих элементах. Строка null считается длиннее чем не имеющая совпадений. Например, «bb*» совпадает с тремя средними символами «abbbc», «(wee|week)(knights|nights)» совпадает со всеми десятью символами «weeknights», а когда «(.*).*» сравнивается с «abc», подвыражение в скобках совпадает со всеми тремя символами; при сравнении «(a*)*» с «bc» получается, что РВ и подвыражение в скобках соответствуют строке null.
Если указано учитывать совпадение независимо от регистра, то все различия по регистру удаляются из алфавита. Когда буква присутствует в различных регистрах вне квадратных скобок, то она трансформируется в выражение в квадратных скобках, содержащее оба регистра, например, 'x' становится «[xX]». Если буква уже заключена в скобки, то к ней добавляется и другой регистр, например, «[x]» становится «[xX]» , а «[^x]» превращается в «[^xX]».
Конкретного ограничения длины РВ(!) не существует. Однако, в переносимых программах не следует использовать РВ более 256 байтов, так как реализация может не принимать таких РВ, но оставаться соответствующей POSIX.
Устаревшие («основные») РВ отличаются по нескольким аспектам. Символы '|', '+' и '?' считаются обычными символами. Для обозначения границ интервалов используются «\{» и «\}», а '{' и '}' сами по себе являются обычными символами. Для обособления подвыражений используются «\(» и «\)», а '(' и ')' сами по себе являются обычными символами. Символ '^' является обычным символом за исключением того случая, когда он стоит в начале РВ или(!) в начале подвыражения в круглых скобках; символ '$' является обычным символом, кроме того случая, когда он стоит в конце РВ или(!) в конце подвыражения в круглых скобках; символ '*' является обычным, если он стоит в начале РВ или в начале подвыражения в круглых скобках (возможно, после символа '^' в самом начале).
Кроме этого, существует ещё один тип атома — обратная ссылка: '\' с последующей за ней ненулевой десятичной цифрой d соответствует той самой последовательности, что и d-е подвыражение в скобках (нумерация подвыражений считается по их открывающим круглым скобкам, слева направо). Пример: «\([bc]\)\1» соответствует «bb» или «cc», но не «bc».
ДЕФЕКТЫ
Наличие двух видов РВ — вынужденная мера.В имеющейся на данный момент документации POSIX.2 указано, что символ ')' при отсутствии '('; считается обычным; это непреднамеренная опечатка, которая будет исправлена. Не полагайтесь на это.
Обратные ссылки — также вынужденная мера, вызывают серьёзные проблемы эффективности в реализациях. Также они не имеют подробного определения (например, «a\(\(b\)*\2\)*d» соответствует «abbbd»?).
Определение в POSIX.2 совпадения при отключении учёта регистра тоже очень туманное. Определение типа «один регистр замещает все остальные», по мнению некоторых специалистов, не является правильным.