Grep регулярное выражение результат не так, как ожидалось?

418
Stilez

Использование FreeBSD 11.1:

#!/bin/sh  if printf 'abcde.fgh' | grep -iEq '^[^][$^*_-]'; then echo "test 1 success" else echo "test 1 fail" fi  echo  if printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'; then echo "test 2 success" else echo "test 2 fail" fi 

Выход:

test 1 success  grep: Unmatched [ or [^ test 2 fail 

Но AFAICT это должно дать тот же результат. Они оба содержат условие для первого символа (только), что оно не входит в список указанных не алфавитных символов. Разбивка регулярного выражения:

  • ^ = начало строки
  • [^...] = соответствует, если ни один из этих символов
  • В списке ]должен быть первый символ, ^не должен быть первым и - должен быть последним. Так ][.^$_-действительный список буквенных символов и строка не должна соответствовать любой из них.
  • Чтобы избежать путаницы, обратите внимание, что это означает, что в списке ][буквально "]"и "["символы, а не закрытие и повторное открытие 2 списков.

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

Что мне не хватает? Что-то очень очевидное и простое, наверное?

2

1 ответ на вопрос

3
grawity

Вам не хватает нескольких других правил синтаксиса. В рамках расширения в скобках, кроме простых диапазонов, есть также несколько типов многосимвольных выражений, которые начинаются с [. (См. Руководство regex (7) для Linux или FreeBSD по адресу «За исключением этих и некоторых комбинаций, использующих« [» (см. Следующие абзацы)».) Это:

  • Элементы сортировки: [..]
  • Классы эквивалентности: [==]
  • Классы персонажей: [::]

(Возможно, вы видели или использовали такие выражения как [[:digit:]]- это на самом деле класс символов, [:digit:]который оказался единственным элементом […]расширения в скобках.)

Так что в вашем случае, поскольку .происходит сразу после a [, они распознаются как начальный разделитель элемента сортировки. GNU grep 3.1 имеет правильное сообщение об ошибке:

$ printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]' grep: Unmatched [, [^, [:, [., or [= 

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

Ааа. Имеет смысл. Я не искал другой синтаксис класса мультихарактер, который мог бы напоминать, так что это было далеко от моих горизонтов. Спасибо! Stilez 5 лет назад 0

Похожие вопросы