Пятница, 27.12.2024
TiM
Меню сайта
Категории раздела
Мои статьи [9]
1С Бухгалтерия [1]
Arduino / ATMEGA [10]
ESP8266 [1]
OrangePi PC и Raspberry Pi 2 Model B V1.1 [4]
Шаговые двигатели [1]
PHPProBid [0]
CMS DLE (DataLife Engine) [0]
CMS Joomla [13]
SugarCRM [5]
Базы данных [5]
PHP скрипты [16]
Bash и скрипты [27]
IP АТС Elastix / Asterisk [12]
CentOS [6]
Debian [8]
Lubuntu / LinuxMINT [29]
Windows [28]
Умный дом [1]
Сервера [16]
Natural Selection [1]
System Shock 2 [1]
Форма входа
Главная » Статьи » Мои статьи

Использование регулярных выражений (regex) в Linux

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

Начну с того, что существует несколько разновидностей регулярных выражений:

1. Традиционные регулярные выражения (они же основные, базовые и basic regular expressions (BRE))

  • синтаксис данных выражений определен, как устаревший, но тем не менее до сих пор широко распространен и  используется многими утилитами UNIX
  • Основные регулярные выражения включают в себя следующие метасимволы (об их значениях ниже):
    • .
    • [ ]
    • [^ ]
    • ^
    • $
    • *
    • \{ \} — первоначальный вариант для { } (в расширенных)
    • \( \) — первоначальный вариант для ( )(в расширенных)
    • \n, где n — номер от 1 до 9
  • Особенности использования данных метасимволов:
    • Звёздочка должна следовать после выражения, соответствующего единичному символу. Пример: [xyz]*.
    • Выражение \(блок\)* следует считать неправильным. В некоторых случаях оно соответствует нулю или более повторений строки блок. В других оно соответствует строке блок*.
    • Внутри символьного класса специальные значения символов, в основном, игнорируются. Особые случаи:
    • Чтобы добавить символ ^ в набор, его следует поместить туда не первым.
    • Чтобы добавить символ -в набор, его следует поместить туда первым или последним. Например:
      • шаблон DNS-имени, куда могут входить буквы, цифры, минус и точка-разделитель: [-0-9a-zA-Z.];
      • любой символ, кроме минуса и цифры: [^-0-9].
    • Чтобы добавить символ [ или ]в набор, его следует поместить туда первым. Например:
      • [][ab] соответствует ], [, a или b.

2. Расширенные регулярные выражения (они же extended regular expressions (ERE))

  • Синтаксис данных выражений аналогичен синтаксису основных выражений, за исключением:
    • Отменено использование обратной косой черты для метасимволов { } и ( ).
    • Обратная косая черта перед метасимволом отменяет его специальное значение.
    • Отвергнута теоретически нерегулярная конструкция \n.
    • Добавлены метасимволы +, ?, |.

3. Регулярные выражения, совместимые с Perl (они же Perl-compatible regular expressions (PCRE))

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

Далее немного поговорим о синтаксисе регулярных выражений.

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

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

Перечисление |

Вертикальная черта (|) разделяет допустимые варианты, можно сказать - логическое ИЛИ. Например, «gray|grey» соответствует gray или grey.

Группировка или объединение ( )

Круглые скобки используются для определения области действия и приоритета операторов. Например, «gray|grey» и «gr(a|e)y» являются разными образцами, но они оба описывают множество, содержащее gray и grey.

Квантификация {} ? * +

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

{m,n}

общее выражение, повторений может быть от m до n включительно.

{m,}

общее выражение, m и более повторений.

{,n}

общее выражение, не более n повторений.

{n}

ровно n повторений.

?

Знак вопроса означает 0 или 1 раз, то же самое, что и {0,1}. Например, «colou?r» соответствует и color, и colour.

*

Звёздочка означает 0, 1 или любое число раз ({0,}). Например, «go*gle» соответствует ggle, gogle, google и др.

+

Плюс означает хотя бы 1 раз ({1,}). Например, «go+gle» соответствует gogle, google и т. д. (но не ggle).

Конкретный синтаксис данных регулярных выражений зависит от реализации. (то есть в базовых регулярных выражениях символы { и } - экранируются обратным слешем)

Метасимволы, говоря простым языком - это символы, которые не соответствуют своему реальному значению, то есть символ . (точка) - это не точка, а любой один символ, и т.п. прошу ознакомиться с метасимволами и их значениями:

. соответствует одному любому символу
[что-то] Соответствует любому единичномусимволу из числа заключённых в скобки. При этом:Символ «-» интерпретируется буквально только в том случае, если он расположен непосредственно после открывающей или перед закрывающей скобкой: [abc-] или [-abc]. В противном случае, он обозначает интервал символов.Например, [abc] соответствует «a», «b» или «c». [a-z] соответствует буквам нижнего регистра латинского алфавита. Эти обозначения могут и сочетаться: [abcq-z] соответствует a, b, c, q, r, s, t, u, v, w, x, y, z.Чтобы установить соответствие символам «[» или «]», достаточно, чтобы закрывающая скобка была первым символом после открывающей: [][ab] соответствует «]», «[», «a» или «b».Если значение в квадратных скобах предварено символом ^, то значение выражения соответствует единичному символу из числа тех, которых нет в скобках. Например, [^abc] соответствует любому символу, кроме «a», «b» или «c». [^a-z] соответствует любому символу, кроме символов нижнего регистра в латинском алфавите.
^ Соответствует началу текста (или началу любой строки, если режим построчный).
$ Соответствует концу текста (или концу любой строки, если режим построчный).
\(\) или ( ) Объявляет «отмеченное подвыражение» (сгруппированное выражение), которое может быть использовано позже (см. следующий элемент: \n). «Отмеченное подвыражение» также является «блоком». В отличие от других операторов, этот (в традиционном синтаксисе) требует бэкслеша, в расширенном и Perl символ \ - не нужен.
\n Где n — это цифра от 1 до 9; соответствует n-му отмеченному подвыражению (например (abcd)\0, то есть символы abcd отмечены нулем). Эта конструкция теоретически нерегулярна, она не была принята в расширенном синтаксисе регулярных выражений.
*
  • Звёздочка после выражения, соответствующего единичному символу, соответствует нулю или более копий этого (предшествующего) выражения. Например, «[xyz]*» соответствует пустой строке, «x», «y», «zx», «zyx», и т. д.
  • \n*, где n — это цифра от 1 до 9, соответствует нулю или более вхождений для соответствия n-го отмеченного подвыражения. Например, «\(a.\)c\1*» соответствует «abcab» и «abcaba», но не «abcac».

!!! Выражение, заключённое в «\(» и «\)» и сопровождаемое «*», следует считать неправильным. В некоторых случаях, оно соответствует нулю или более вхождений строки, которая была заключена в скобки. В других, оно соответствует выражению, заключённому в скобки, учитывая символ «*».

\{x,y\} Соответствует последнему (предстоящему) блоку, встречающемуся не менее x и не более y раз. Например, «a\{3,5\}» соответствует «aaa», «aaaa» или «aaaaa». В отличие от других операторов, этот (в традиционном синтаксисе) требует бэкслеша.
.* Обозначение любого количества любых символов между двумя частями регулярного выражения.

Метасимволы нам помогают использовать различные соответствия. Но как же представить метасимвол обычным символом, то есть символ [ (квадратная скобка) значением квадратной скобки? Просто:

  • необходимо предварить (экранировать) метасимвол (. * + \ ? [ ] { } ) обратным слешем. Например \. или \[

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

POSIX класс аналогично обозначение
[:upper:] [A-Z] символы верхнего регистра
[:lower:] [a-z] символы нижнего регистра
[:alpha:] [A-Za-z] символы верхнего и нижнего регистра
[:alnum:] [A-Za-z0-9] цифры, символы верхнего и нижнего регистра
[:digit:] [0-9] цифры
[:xdigit:] [0-9A-Fa-f] шестнадцатеричные цифры
[:punct:] [.,!?:…] знаки пунктуации
[:blank:] [ \t] пробел и TAB
[:space:] [ \t\n\r\f\v] символы пропуска
[:cntrl:]   символы управления
[:graph:] [^ \t\n\r\f\v] символы печати
[:print:] [^\t\n\r\f\v] символы печати и символы пропуска

В regex есть такое понятие как:

Жадность regex

Постараюсь описать как можно понятней. Допустим, мы хотим найти все HTML теги в каком-то тексте. Локализовав задачу, мы хотим найти значения заключенные между < и >, вместе с этими самыми скобками. Но мы знаем, что теги имеют разную длину и самих тегов, как минимум штук 50. Перечислять их все , заключив в метасимволы [] - задача слишком трудоемкая. Но мы знаем, что у нас есть выражение .* (точка звездочка), характеризующее любое число любых символов в строке. С помощью данного выражения мы попытаемся найти в тексте (<p>Итак, <strong>Как создать RAID уровня 10/50 на контроллере LSI MegaRAID (актуально и для: Intel SRCU42x, Intel SRCS16):</strong><span id="more-2058"></span></p>) все значения между < и >. В результате, этому выражению будет соответствовать ВСЯ строка. почему, потому что регекс - ЖАДЕН и старается захватить ЛЮБОЕ ВСЕ количество символов между < и >, соответственно вся строка, начиная <p>Итак,... и заканчивая ...</span></p> будет принадлежать данному правилу!

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

  • учесть символы, не соответствующие желаемому образцу (например: <[^>]*> для вышеописанного случая)
  • избавить от жадности, добавив определении квантификатора, как нежадного:
    • *? - «не жадный» («ленивый») эквивалент *
    • +? - «не жадный» («ленивый») эквивалент +
    • {n,}? - «не жадный» («ленивый») эквивалент {n,}
    • .*? - «не жадный» («ленивый») эквивалент .*

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

Регулярные выражения в POSIX аналогичны традиционному Unix-синтаксису, но с добавлением некоторых метасимволов:

+

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

?

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

|

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

Также было отменено использование обратной косой черты: \{…\} становится {…} и \(…\) становится (…).

В завершение поста, приведу некоторые примеры использования regex:

[regex@regexp k-max.name]$ cat text1
1 apple
2 pear
3 banana
[regex@regexp k-max.name]$ grep p text1
1 apple
2 pear
[regex@regexp k-max.name]$ grep pea text1
2 pear
[regex@regexp k-max.name]$ grep "p*" text1
1 apple
2 pear
3 banana
[regex@regexp k-max.name]$ grep "pp*" text1
1 apple
2 pear
[regex@regexp k-max.name]$ grep "x" text1
[regex@regexp k-max.name]$ grep "x*" text1
1 apple
2 pear
3 banana
[regex@regexp k-max.name]$ cat text1 | grep "l\|n"
1 apple
3 banana
[regex@regexp k-max.name]$ echo -e "find an\n* here" | grep "\*"
* here
[regex@regexp k-max.name]$ grep "pp\+" text1 # строки, с содержанием одной р и 1 и более р
1 apple
[regex@regexp k-max.name]$ grep "pl\?e" text1
1 apple
2 pear
[regex@regexp k-max.name]$ grep "pl\?e" text1 # pe с возможным символом l
1 apple
2 pear
[regex@regexp k-max.name]$ grep "p.*r" text1 # p, в строках где есть r
2 pear
[regex@regexp k-max.name]$ grep "a.." text1 # строки с a, за которой следует как минимум 2 символа
1 apple
3 banana
[regex@regexp k-max.name]$ grep "\(an\)\+" text1 # Поиск более повторения an
3 banana
[regex@regexp k-max.name]$ grep "an\(an\)\+" text1 # поиск 2х повторений an
3 banana
[regex@regexp k-max.name]$ grep "[3p]" text1 # поиск строк, где есть 3 или p
1 apple
2 pear
3 banana
[regex@regexp k-max.name]$ echo -e "find an\n* here\nsomewhere." | grep "[.*]"
* here
somewhere.
[regex@regexp k-max.name]$ # Ищет символы от 3 до 7
[regex@regexp k-max.name]$ echo -e "123\n456\n789\n0" | grep "[3-7]"
123
456
789
[regex@regexp k-max.name]$ # Ищем цифру, за которой до конца строки нет букв n и r
[regex@regexp k-max.name]$ grep "[[:digit:]][^nr]*$" text1
1 apple
[regex@regexp k-max.name]$ sed -e '/\(a.*a\)\|\(p.*p\)/s/a/A/g' text1 # замена а на А во всех строках, где после а идет а или после р идет р
1 Apple
2 pear
3 bAnAnA
[regex@regexp k-max.name]$ sed -e '/^[^lmnXYZ]*$/s/ear/each/g' text1 # замена ear на each в строках не начинающихся на lmnXYZ
1 apple
2 peach
3 banana
[regex@regexp k-max.name]$ echo "First. A phrase. This is a sentence." |\ # замена последнего слова в предложении на LAST WORLD.
&amp;amp;gt; sed -e 's/ [^ ]*\./ LAST WORD./g'
First. A LAST WORD. This is a LAST WORD.

 

Источник: http://www.k-max.name/linux/ispolzovanie-regulyarnyx-vyrazhenij-regex-v-linux/

Категория: Мои статьи | Добавил: Timur (21.07.2016)
Просмотров: 1483
Поиск
Статистика

Онлайн всего: 3
Гостей: 3
Пользователей: 0
YANDEX
Яндекс.Метрика
Сайты
  • Харьковский Юридический Альянс
  • Оцифровка кинопленки
  • TiM ©
    Харьков 2024