Преобразовать весь текст из прописных в строчные и наоборот?


17

У меня вопрос, как я могу преобразовать весь текст из прописных в строчные и наоборот? То есть поменять регистры всех букв. Это должно быть сделано с sedзаменой как-то.


4
trбыло бы более подходящим, чем sed.
— Чороба

Ответы:


20

Вот прямой путь в sed:

$ echo qWeRtY | sed -e 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/'
QwErTy

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

$ echo qWeRtY | sed -E 's/([[:lower:]])|([[:upper:]])/\U\1\L\2/g'
QwErTy

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

perl (ограничено буквами ASCII):

$ echo qWeRtY | perl -pe 'y/[a-z][A-Z]/[A-Z][a-z]/'
QwErTy

perl (в более общем смысле):

$ echo 'αΒγ' | perl -Mopen=locale -pe 's/(\p{Ll})|(\p{Lu})/uc($1).lc($2)/ge'
ΑβΓ

3
Ваш второй предполагает наличие GNU sedи альтернативного регистра на входе. Используйте sed -re 's/([[:lower:]]?)([[:upper:]]?)/\U\1\L\2/g'вместо этого (все еще специфично для GNU). Первая конвертирует только 26 латинских букв ASCII, а вторая - любую букву, распознаваемую как таковую вашей локалью. trОдин имеет смысл только в ASCII местах. perlОдин работает только для ASCII латинских букв.
— Стефан Шазелас

16

POSIXly, это не может быть сделано, sedкроме как путем предоставления полного набора букв, которые вы хотите транслитерировать, как показано @cuonglm .

Это может быть сделано с помощью tr, и вот для чего tr(транслитерация):

tr '[:lower:][:upper:]' '[:upper:][:lower:]'

Однако в Linux у него есть ограничения. Из 3 trреализаций, обычно встречающихся в системах на основе Linux:

  • с GNU trэто работает только для однобайтовых наборов символов. Например, Stéphane Chazelasв локалях UTF-8 это дает sTéPHANE cHAZELASвместо sTÉPHANE cHAZELAS. Это известное ограничение GNU tr.
  • с trпомощью инструмента семейной реликвии, это не работает (вы понимаете stéphane chazelas).
  • Это не та вещь, которую trбудет делать busybox .

На FreeBSD это работает нормально, хотя. Вы ожидаете, что он будет работать нормально и в сертифицированных системах Unix.


В bashоболочке есть специальный оператор для этого:

in=AbCdE
out=${in~~}

С zsh -o extendedglob:

out=${in//(#b)(([[:lower:]])|([[:upper:]]))/${(U)match[2]}${(L)match[3]}}

Так что в настольном мире только OSX делает это? Почему это не может работать? Это просто разные реализации, так как кажется, что в шестнадцатеричном значении есть постоянное смещение между строчной версией акцентированного символа и его заглавной копией?

1
@освет, не знаю, что ты имеешь в виду под миром рабочего стола . AFAICS, проблема с GNU, большинство Unices имеют «рабочие столы». Кроме ASCII и некоторых кодировок iso8859, я не знаю, что вы можете обобщить шестнадцатеричное смещение, и это не имеет смысла для кодировок, таких как UTF-8. Например, в UTF-8 заглавными буквами ⴠ(e2 b4 a0) является Ⴠ(e1 83 80); оба i(69) и ı(c4 b1) имеют I(49) в верхнем регистре (за исключением турецких языков, где iставится İ). Причина, по которой он не работает с GNU, trзаключается в том, что GNU trработает с байтами, а не с символами.
— Стефан Шазелас

Я имею в виду мейнстрим, но на самом деле это не имеет смысла, так что спасибо за внимание. Я просто посмотрел на французские акцентированные символы (и на самом деле просто «é») и сделал очень упрощенные предположения, снова забыв, что речь идет о байтах. Но семейная реликвия одна? Я пойду читать этот ответ снова!

1
@lightÉ, для семейной реликвии это другая проблема, кажется, она поддерживает только одно вхождение [:lower:]или [:upper:](так что первое игнорируется). Даже на французском œ -> Œесть c5 93 -> c5 92в UTF-8 и bd -> bcв iso8859-15.
— Стефан Шазелас

2

Хотя это имеет те же ограничения, которые уже упоминались в качестве trрешения, предложенного Стефаном Шазеласом, это еще один способ сделать это:

{   echo QWERTYqwerty | dd conv=lcase
    echo QWERTYqwerty | dd conv=ucase 
} 2>/dev/null

ВЫХОД

qwertyqwerty
QWERTYQWERTY

Я сваливать stderrв /dev/nullтам , потому что ddтакже предоставляет статистику всех своих операций на 2дескрипторе файла. Это может быть полезно в зависимости от того, что вы делаете, но не для этой демонстрации. Все остальные вещи, с которыми вы можете работать, по- ddпрежнему применимы, например:

echo QWERTYqwerty | dd bs=1 cbs=6 conv=unblock,ucase 2>/dev/null

ВЫХОД:

QWERTY
QWERTY

Это не меняет дело, хотя (как в aBcне конвертируется в AbC).
— Стефан Шазелас

1
@ StéphaneChazelas - правда, но если я не понял, это был не вопрос, не так ли?
— Микесерв

2

Если вашей главной целью является преобразование файла из нижнего класса в верхний класс, почему бы вам не использовать trи STDOUTпреобразовать ваш файл:

$cat FILENAME | tr a-z A-Z > FILENAME2

где FILENAME ваш оригинальный файл? Где FILENAME2ваш конвертированный выходной файл.


Это не работает с акцентированными символами, как éнапример (по крайней мере, в моем файле).
— Сигур

1

используя awk:

awk '{print tolower($0)}' file.txt | tee file.txt

ты уверен, что это сработает? >file.txtбудет начинаться с усечения файла
— iruvar

2
Тогда вы явно не пробовали это.
— Стефан Шазелас

0

ruby для этого есть строковый метод, похожий на использование из командной строки perl

$ echo 'qWeRtY' | ruby -pe '$_.swapcase!'
QwErTy

Смотрите также ruby-doc Encoding

$ ruby -e 'puts Encoding.default_external'
UTF-8
$ echo 'αΒγ'  | ruby -pe '$_.swapcase!'
ΑβΓ

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.