Попытка удалить символы конца слова с помощью sed regex

Попытка удалить символы конца слова с помощью sed regex

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

  • Входная строка: Привет Привет
  • Ожидаемый результат: Ад Ад

Хорошие новости: я могу удалить букву «о», если она находится в конце строки:

$ echo 'Hello Hello' |sed 's/\(.*\)o/\1/g'
Hello Hell
$ echo 'Hello Hello' |sed 's/\(.*\)o$/\1/g'
Hello Hell

Плохая новость: я не могу удалить его из слов, стоящих ранее в строке. Я пробовал это со всеми символами-якорями, которые только мог придумать. Результатом является то, что ни один из конечных «o» слова не удаляется:

$ echo 'Hello Hello' |sed 's/\(.*\)o\b/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\>/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\W/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\s/\1/g'
Hello Hello

Не могли бы вы помочь мне вернуть здравомыслие, объяснив, что я делаю не так?

Обновление: У меня сложилось четкое впечатление, что моя машина выдает результаты, отличные от результатов других людей. Я использую окно терминала на моем Macbook. Если кто-то может пролить свет на это, пожалуйста, сообщите мне.

решение1

echo 'Hello Hello' | sed 's/o$//'

кажется мне более полезным, чем ваш

echo 'Hello Hello' | sed 's/\(.*\)o$/\1/g'

В вашем вопросе говорится, что выход

echo 'Hello Hello' | sed 's/\(.*\)o\b/\1/g'

было Hello Hello, но для меня это так Hello Hell. Вы можете исправить это на

echo 'Hello Hello' | sed 's/\([^o]*\)o\b/\1/g'

но

echo 'Hello Hello' | sed 's/o\b//g'

Мне кажется, так лучше.

решение2

Удаление oв конце слов — это удаление ao между символом слова и несловесным символом (или EOL), поэтому:

sed -r 's/(\w)o(\W|$)/\1\2/g'

решение3

Мне интересно, spaceне является ли ваш разделитель слов чем-то другим. Попробуйте что-то вроде следующего:

$ echo hello hello | sed -e 's/o / /g;s/o$//'
hell hell

Проблема с этим примером в том, что вам также придется сделать то же самое для .and ,и любого другого разделителя слов. Сопоставьте, oза которым следует другой определенный символ с помощью []like o[ \.,]. По какой-то причине это не работает для EOL $, поэтому добавьте еще одну строку поиска с помощью ;. Пример:

$ echo hello hello, hello. toot hello | sed -e 's/o\([ \.,]\)/\1/g;s/o$//'
hell hell, hell. toot hell
$ echo $SHELL
/bin/bash
$ sed --version
sed (GNU sed) 4.4
$ set | grep IFS
IFS=$' \t\n'

решение4

Я попробовал это со всеми символами-якорями, которые только смог придумать.

Это не якоря, а то, что у вас жадный матч со звездочкой. Выражение \(.*\)oсовпадаеткак можно длиннее, поэтому он съест все до самогопоследний o. Это может совпадать oи с более ранними .

Но тогда бесполезно что-то захватывать и возвращать обратно, можно просто удалить и то, \(.*\)и другое \1полностью.

Итак, это (по крайней мере в GNU sed) удалит o«'» в конце слов:

sed 's/o\>//g' 
sed 's/o\b//g' 

Это, конечно, только в конце строки:

sed 's/o$//g' 

И это удалит o, а также следующий за ним символ, не являющийся словом (например, пробел после Hello):

sed 's/o\W//g' 

Если ваш sedне поддерживает \</ \>или \b, вам придется сделать что-то еще. Это будет соответствовать oследующему небуквенно-цифровому символу или концу строки:

$ echo "jello, jello" | sed -E -e 's/o([^[:alnum:]]|$)/\1/g'
jell, jell

Это работает, например, в sedОС OS X/macOS.


Регулярные выражения Perl поддерживают добавление вопросительного знака к *или , +чтобы сделать их нежадными. Тогда они будут соответствоватьсамый короткийвозможная строка:

echo "jello, jello" | perl -pe 's/(.*?)o/$1/g'
jell, jell

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