Как сделать первую букву каждого слова заглавной, используя sed в OSX

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

 echo "my string" | sed 's/\b\(.\)/\u\1/g'

Выход:

 my string

Что я делаю не так?

Спасибо


person Ares    schedule 12.08.2015    source источник


Ответы (4)


Это уже было рассмотрено: Заглавная буква слов с использованием SED

Я получаю правильное поведение с GNU sed, но не со стандартным BSD sed, который поставляется с OS X. Я думаю, что \u "регулярное выражение" - это вещь GNU. Как насчет «порт установить gsed»?

Редактировать: если вы действительно хотите использовать BSD sed, что я бы не рекомендовал (потому что команда становится очень уродливой), то вы можете сделать следующее: sed -E "s:([^[:alnum:]_]|^)a:\1A:g; s:([^[:alnum:]_]|^)b:\1B:g; s:([^[:alnum:]_]|^)c:\1C:g; s:([^[:alnum:]_]|^)d:\1D:g; s:([^[:alnum:]_]|^)e:\1E:g; s:([^[:alnum:]_]|^)f:\1F:g; s:([^[:alnum:]_]|^)g:\1G:g; s:([^[:alnum:]_]|^)h:\1H:g; s:([^[:alnum:]_]|^)i:\1I:g; s:([^[:alnum:]_]|^)j:\1J:g; s:([^[:alnum:]_]|^)k:\1K:g; s:([^[:alnum:]_]|^)l:\1L:g; s:([^[:alnum:]_]|^)m:\1M:g; s:([^[:alnum:]_]|^)n:\1N:g; s:([^[:alnum:]_]|^)o:\1O:g; s:([^[:alnum:]_]|^)p:\1P:g; s:([^[:alnum:]_]|^)q:\1Q:g; s:([^[:alnum:]_]|^)r:\1R:g; s:([^[:alnum:]_]|^)s:\1S:g; s:([^[:alnum:]_]|^)t:\1T:g; s:([^[:alnum:]_]|^)u:\1U:g; s:([^[:alnum:]_]|^)v:\1V:g; s:([^[:alnum:]_]|^)w:\1W:g; s:([^[:alnum:]_]|^)x:\1X:g; s:([^[:alnum:]_]|^)y:\1Y:g; s:([^[:alnum:]_]|^)z:\1Z:g;"

person Goens    schedule 12.08.2015
comment
К сожалению, установка gsed не является жизнеспособным вариантом. Я пишу сценарий, который будет использоваться в основном другими пользователями OSX. - person Ares; 12.08.2015
comment
Тогда я думаю, что sed не подходит для этой работы, так как вы не получите заглавные буквы без расширений GNU, вы можете попробовать, например, perl (не знаю о awk). Если вам действительно нужно сделать это с помощью BSD sed, то вам придется делать это буква за буквой... - person Goens; 12.08.2015
comment
Я пришел к такому же выводу. В итоге я использовал bash for loop и tr. - person Ares; 12.08.2015
comment
@Ares Каждый раз, когда вы пишете цикл в оболочке только для управления текстом, у вас неправильный подход (погуглите). Просто используйте awk, так как манипулирование текстом — это то, для чего он был изобретен. - person Ed Morton; 12.08.2015

Учитывая ваш образец ввода, это будет работать в любом awk:

$ echo 'my string' | awk '{for (i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)} 1'
My String

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

person Ed Morton    schedule 12.08.2015

Вот решение sed, которое работает на OSX:

echo 'my string
ANOTHER STRING
tHiRd StRiNg' | sed -En '
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
:loop
h
s/^(.*[^a-zA-Z0-9])?([a-z]).*$/\2/
t next
b end
:next
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
G
s/^(.+)\n(.*[^a-zA-Z0-9])?[a-z](.*)$/\2\1\3/
t loop
:end
p
'

Output:
My String
Another String
Third String

Команда sed работает следующим образом:

  1. sed вводит строку, а первая команда y преобразует все прописные буквы в строчные.
  2. Команды от :loop до t loop образуют цикл, который выполняется один раз для каждого слова в текущей строке, начиная с заглавной буквы каждого слова.
  3. Когда в текущей строке больше нет слов для заглавных букв, команда p печатает строку, а sed вводит следующую строку.

Вот как работает цикл:

  1. Команда h сохраняет строку в том виде, в котором она находится в данный момент, в ячейку удержания.
  2. Команда first s ищет первую букву первого слова без заглавной буквы. Если такое слово найдено, команда s сохраняет свою первую букву в пространстве шаблонов, а команда t переходит к метке :next. Если такое слово не найдено, что указывает на то, что больше нет слов для заглавных букв, вместо этого выполняется команда b, переходя к метке :end для вывода и завершения обработки текущей строки.
  3. Если было найдено слово, требующее капитализации, выполнение возобновляется с метки :next, а команда y преобразует первую букву, которая сейчас находится в пространстве шаблона, из строчной в прописную.
  4. Команда G добавляет непреобразованную версию текущей строки из области хранения в конец области шаблона.
  5. Вторая команда s восстанавливает текущую строку, заменяя первую букву слова, обрабатываемого в данный момент, его версией с заглавной буквы.
  6. Команда t переходит к метке :loop для поиска следующего слова, которое нужно писать с заглавной буквы.

Тестирование скорости выполнения показало, что текущий подход sed выполняется примерно с той же скоростью, что и решение awk, представленное Эдом Мортоном.

person scolfax    schedule 26.10.2016

Пытаться:

echo "my string" | sed -r 's/\b(.)/\u\1/g'
person Diego Torres Milano    schedule 12.08.2015
comment
Я запускаю это на OSX. Я получаю sed: недопустимый вариант -- r - person Ares; 12.08.2015
comment
в OSX используйте -E (я думаю) - person Diego Torres Milano; 12.08.2015
comment
sed: 1: s/\b(.)/\u\1/g: \1 не определено в RE - person Ares; 12.08.2015
comment
Это может не работать в OSX (не тестировалось), но отлично работает в Bash на Mint. Спасибо, это было то, что я искал. - person Roel Van de Paar; 03.10.2020