Почему '[az] *' соответствует не алфавитным строкам?

9

У меня есть файл alphanumс этими двумя строками:

123 abc
this is a line

Я не понимаю, почему, когда я бегу sed 's/[a-z]*/SUB/' alphanum, я получаю следующий вывод:

SUB123 abc
SUB is a line

Я ожидал:

123 SUB
SUB is a line

Я нашел исправление (используйте sed 's/[a-z][a-z]*/SUB/'вместо этого), но я не понимаю, почему оно работает, а мое нет.

Вы можете помочь?

Фахер Мокадем
источник
@ Kamaraj, тот похож на него, но имеет шаблон оболочки против регулярных выражений путаницы сверху (и ответы сосредоточены на первом, так как это то, что ls foo*там используется). Но в любом случае, если вы обнаружите дубликаты вопросов, я думаю, вы также сможете пометить их как таковые.
ilkkachu
Зайдите на regexr.com, чтобы посмотреть живые изображения и объяснить
RozzA
@RozzA Обратите внимание, что веб-сайт, на который вы ссылаетесь, поддерживает регулярные выражения Javascript и Perl, а не регулярные выражения POSIX.
Кусалананда

Ответы:

28

Шаблон [a-z]*соответствует нулю или нескольким символам в диапазоне aдо z( фактические символы зависят от текущей локали). В самом начале строки 123 abc(таких как шаблон соответствует) ноль таких символов , а также четыре из них в начале this is a line.

Если вам нужно хотя бы одно совпадение, используйте [a-z][a-z]*или [a-z]\{1,\}или включите расширенные регулярные выражения с помощью sed -Eи используйте [a-z]+.

Чтобы визуализировать совпадения шаблона, добавьте скобки вокруг каждого соответствия:

$ sed 's/[a-z]*/(&)/' file
()123 abc
(this) is a line

Или, чтобы увидеть все совпадения по строкам:

$ sed 's/[a-z]*/(&)/g' file
()1()2()3() (abc)
(this) (is) (a) (line)

Сравните этот последний результат с

$ sed -E 's/[a-z]+/(&)/g' file
123 (abc)
(this) (is) (a) (line)
Кусалананда
источник
7
Технически [a-z]соответствует элементам сопоставления, которые могут состоять из более чем одного символа. Например, в некоторых венгерских регионах [a-z]матчиdzs
Стефан Шазелас
12

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

Совпадения нулевой длины могут быть немного проблематичными, и, как вы видели, решение состоит в том, чтобы изменить шаблон так, чтобы для него требовался хотя бы один символ. С расширенными регулярными выражениями вы могли бы +для этого:sed -E 's/[a-z]+/SUB/'

Для развлечения попробуйте:

echo 'less than 123 words' | sed 's/[0-9]*/x/g'
ilkkachu
источник