Удалить пробелы после отдельных заглавных букв с помощью sed

Удалить пробелы после отдельных заглавных букв с помощью sed

Я пишу скрипт bash для автоматического создания некоторых других файлов, и мне нужно отформатировать некоторые строки определенным образом. В частности, последняя проблема, с которой я сталкиваюсь, — это форматирование строки, которая содержит отдельные заглавные буквы, и слова, которое начинается с заглавной буквы. Например:

O S D Settingsнеобходимо статьOSD Settings

У меня есть команда sed, которая удаляет первый пробел, но также удаляет "D" (т.е. O S D Settings-> OS Settings). Эта команда:

O S D Settings | sed 's/ \([A-Z]\)* \(A-Za-z]*\)/\1/g'

Кто-нибудь знает, как удалить пробелы между отдельными заглавными буквами, не потеряв ни одной буквы?

решение1

Это касается таких имен, как A B ChadwickиA B C D'Souza

Текст, такой как A B cdeи A B CDEне изменяется.

Он использует два временных нулевых символа \x00для обозначения изменений (для каждого имени) по мере продвижения по строке, удаляя пробелы.

:Nи :Sестьфилиал-кметки (подойдет любое имя)
tи bявляются инструкциями по ветвлению.
tветвления при успешной замене в предыдущей s/../../команде.
bветвления без условий.

sed -r ":N                                                # loop per name
         /(\<[A-Z]\> )+[A-Z][a-z']/{                      # line needs action
             s/((\<[A-Z]\> )+)([A-Z][a-z'])/\x00\1\x00\3/ # add \x00 markers
            :S                                            # loop per space
             s/(\x00[A-Z]+) (\<[A-Z]\>)/\1\2/             # delete a space
             t S                                          # any more spaces? 
             b N                                          # any more names?
         }; s/\x00//g"                                    # remove \x00

решение2

Сложновато с sed, но если perlвсе в порядке, то можно сделать так

echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'

Это сложно, sedпоскольку не поддерживает упреждающие утверждения.

Тесты:

echo O S D | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D. | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo One O DDE T. S Asdf Q R Tee | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D\  | perl -p -e 's/([A-Z]) (?=.([^\w]|$))/$1/g'

Если вам нужно неаккуратное решение с sed, попробуйте

echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'

Это работает для вашего образца, но не сработает в других случаях.

Тесты:

echo O S D | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D. | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo One O DDE T. S Asdf Q R Tee | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D\  | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'

решение3

Это может вам подойти:

echo "O S D Settings and B T W and A B C D'Souza too F Y I" |
sed ':a;s/\(\<[[:upper:]]\>\) \(\<[[:upper:]]\>\([^'\'']\|$\)\)/\1\n\2/g;ta;s/\n//g'
OSD Settings and BTW and ABC D'Souza too FYI

Объяснение:

Используйте символ, которого нет в исходной строке, чтобы заменить пробелы, которые вы хотите удалить, затем удалите выбранный символ во всей строке. \n— хороший кандидат, поскольку он не может существовать в обычном режиме, поскольку используется sed в качестве разделителя строк.

решение4

В итоге я просто использовал sed с каналами, чтобы получить выражение, которое мне легко понять:

echo O S D Settings | sed 's/\([A-Z][^ ]\)/_\1/g' | sed 's/ //g' | sed 's/_/ /g'

Все, что это делает, это заменяет ненужные мне пробелы на подчеркивание, а затем удаляет их. Спасибо за все ответы!

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