извлечь строку перед цифрами и после подчеркивания

извлечь строку перед цифрами и после подчеркивания

Исходная строка выглядит так:

str-str001-002_01
str-str005-006_05

Я хотел бы извлечь строку перед числом и после подчеркивания, так что это будет выглядеть так:

str-str_01
str-str_05

Я помню, что sed мог разделять шаблоны на группы следующим образом:

 sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'

но он печатает:

str-str0002_01

Затем я вспомнил, что [0-9] — это всего лишь одна цифра, поэтому я попробовал ввести ее со знаком + или *. Тогда это дало пустой результат.

пс: с помощью

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'

Я вижу, что это совпадает 1-0.

Затем я попробовал:

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'

он оставил первые 2 цифры, и только совпадения

1-002

так как же сделать так, чтобы это совпадало001-002

решение1

Это обеспечивает требуемый результат:

sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'

Вывод из вашего примера

str-str_01
str-str_05

Объяснение

  • sed -nE 's/…/…/p'- Используйте ERE, не печатайте строки, если они не совпадают
  • ^- привязка к началу строки
  • ([^0-9]*)- сопоставить максимально длинный шаблон, содержащий хотя бы один нецифровой символ
  • .*_- максимально возможное соответствие (включая отсутствие совпадений), затем " _"
  • ([^_]+)- сопоставить максимально длинный шаблон (не менее одного символа), который не является подчеркиванием
  • $- прикрепить к концу строки
  • \1_\2- заменить всю строку с первым (…)совпадением, " _", и вторым (…)совпадением

Причина, по которой ваши попытки не сработали так, как вы ожидали, заключается в том, что *(and +) является жадным — он потребляет как можно больше символов, соответствующих предыдущему атому. Поэтому для ERE, (.*)([0-9]+)примененного к чему-то вроде abc123, .* потребит abc12, оставив [0-9]+для соответствия только 3. Вам понадобится "не цифра" чтобы ограничить первое совпадение: ([^0-9]*)([0-9]+)получить abcи 123.

решение2

$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05

Команда подстановки здесь сопоставляет и удаляет NNN-NNNстроку, NNNсостоящую из трех цифр.

Чтобы соответствоватьхотя бы одинцифра, используйте 1,вместо 3:

$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05

Это соответствует использованию +в расширенном регулярном выражении. Регулярные выражения, используемые sedпо умолчанию, являются "базовыми" регулярными выражениями и +будут соответствовать литералу плюса. Большинство sedреализаций также поддерживают расширенные выражения с -E:

$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05

Использование *, как в [0-9]*-[0-9]*, не сработает, так как это будет соответствовать тире в str-str(вокруг которого находятся нули).


Если вы чувствуете, что вам действительно нужно сопоставить всю строку и захватить биты, которые вы хотите сохранить, то вы тоже можете это сделать. Следующая команда захватывает начальные нецифровые символы и последний бит, включая подчеркивание:

$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05

Однако, IMHO, это немного сложно расшифровать, и это делает предположения о начале и конце строки, которые вы никогда не упоминали в вопросе. Начало не может, например, содержать цифры перед цифрами, которые вы хотите удалить, и конец строки будет обрезан впоследнийподчеркивание, не обязательно после цифр, которые вы хотите удалить, если в этой части строки есть несколько подчеркиваний.

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

Связанный контент