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


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.