2

Использование 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 это должно дать тот же результат. Они оба содержат условие для первого символа (только), что оно не входит в список указанных не алфавитных символов. Разбивка регулярного выражения:

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

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

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

1 ответ1

3

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

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

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

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .