Czy przekonwertować cały tekst z wielkich na małe i odwrotnie?

17

Moje pytanie brzmi: jak mogę przekonwertować cały tekst z wielkich na małe i odwrotnie? To jest zmiana wielkości liter wszystkich liter. sedJakoś trzeba to zrobić z wymianą.

MEZesUBI
źródło
4
trbyłoby bardziej odpowiednie niż sed.
choroba

Odpowiedzi:

20

Oto prosty sposób na sed:

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

lub w skrócie z GNU sed, pracując z dowolnym znakiem, dla którego w twoim języku istnieje konwersja małych liter <->:

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

jeśli możesz użyć innych narzędzi, takich jak:

perl (ograniczone do liter ASCII):

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

perl (bardziej ogólnie):

$ echo 'αΒγ' | perl -Mopen=locale -pe 's/(\p{Ll})|(\p{Lu})/uc($1).lc($2)/ge'
ΑβΓ
Cuonglm
źródło
3
Twój drugi zakłada GNU sedi zmienną wielkość liter na wejściu. Użyj sed -re 's/([[:lower:]]?)([[:upper:]]?)/\U\1\L\2/g'zamiast tego (wciąż specyficzne dla GNU). Pierwszy konwertuje tylko 26 liter łacińskich ASCII, a drugi konwertuje każdą literę rozpoznaną jako taką przez twoje ustawienia regionalne. Ten trma sens tylko w ustawieniach regionalnych ASCII. Ten perldziała tylko dla łacińskich liter ASCII.
Stéphane Chazelas
16

POSIXly, nie da się tego zrobić sedinaczej niż poprzez dostarczenie pełnego zestawu liter, które chcesz transliterować, jak pokazał @cuonglm .

Można to jednak zrobić za pomocą tri właśnie po to tr(transliteracja):

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

Jednak w systemie Linux ma ograniczenia. Z 3 trimplementacji powszechnie spotykanych w systemach Linux:

  • z GNU tr, który działa tylko dla jednobajtowych zestawów znaków. Na przykład, Stéphane Chazelasw ustawieniach regionalnych UTF-8, to daje sTéPHANE cHAZELASzamiast sTÉPHANE cHAZELAS. To znane ograniczenie GNU tr.
  • z trzestawem narzędzi rodowych, to nie działa (dostajesz stéphane chazelas).
  • Tego nie trzrobi busyboks .

Na FreeBSD działa jednak OK. Można się spodziewać, że będzie działał dobrze również w certyfikowanych systemach uniksowych.


bashPowłoka ma przypisanego operatora na to:

in=AbCdE
out=${in~~}

Z zsh -o extendedglob:

out=${in//(#b)(([[:lower:]])|([[:upper:]]))/${(U)match[2]}${(L)match[3]}}
Stéphane Chazelas
źródło
Czy w świecie komputerów tylko OSX to robi? Dlaczego to nie działa? Czy to tylko różne implementacje, ponieważ wydaje się, że istnieje ciągłe przesunięcie wartości szesnastkowej między wersją akcentowanego znaku z małą literą a jego wielkimi literami?
1
@ illuminÉ, nie jestem pewien, co masz na myśli przez określenie świata komputerów . AFAICS, problem dotyczy GNU, większość Unices ma „komputery stacjonarne”. Poza ASCII i niektórymi zestawami znaków iso8859, nie jestem świadomy, że można uogólnić przesunięcie heksadecymalne, co nie miałoby sensu w przypadku kodowania takiego jak UTF-8. Na przykład w UTF-8, wielkie litery (e2 b4 a0) to (e1 83 80); zarówno i(69), jak i ı(c4 b1) mają I(49) jako wielkie litery (z wyjątkiem tureckich lokalizacji, w których się ipojawia İ). Powodem, dla którego nie działa z GNU, trjest to, że GNU trdziała z bajtami, a nie ze znakami.
Stéphane Chazelas,
W pewnym sensie miałem na myśli główny nurt, ale to naprawdę nie ma sensu, więc dziękuję za uwagi. Właśnie spojrzałem na francuskie znaki akcentowane (a tak naprawdę po prostu „é”) i podjąłem bardzo uproszczone założenia, zapominając ponownie, że chodzi o bajty. Ale ten rodowy? Przeczytam tę odpowiedź jeszcze raz!
1
@ illuminé, w przypadku pamiątki jest to inny problem, wygląda na to, że obsługuje tylko jedno wystąpienie [:lower:]lub [:upper:](więc pierwszy jest ignorowany). Nawet w języku francuskim œ -> Œjest c5 93 -> c5 92w UTF-8 i bd -> bcw iso8859-15.
Stéphane Chazelas,
2

Chociaż ma to już te same ograniczenia, co trrozwiązanie oferowane przez Stéphane Chazelas, jest to inny sposób:

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

WYNIK

qwertyqwerty
QWERTYQWERTY

I zrzucić stderrsię /dev/nulltam, ponieważ ddzapewnia również statystyki wszystkich swoich działań na 2deskryptorze pliku. Może to być przydatne w zależności od tego, co robisz, ale nie było w tej demonstracji. ddNadal obowiązują wszystkie inne rzeczy, które możesz zrobić , na przykład:

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

WYNIK:

QWERTY
QWERTY
mikeserv
źródło
Nie zamienia jednak sprawy (ponieważ in aBcnie jest konwertowany na AbC).
Stéphane Chazelas,
1
@ StéphaneChazelas - prawda, ale chyba że źle zrozumiałem, to nie było pytanie, prawda?
mikeserv
2

Jeśli Twoim głównym celem jest konwersja pliku z klasy niższej do wyższej, dlaczego nie używasz tri STDOUTdo konwersji pliku:

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

Gdzie FILENAMEjest twój oryginalny plik. Gdzie FILENAME2jest przekonwertowany plik wyjściowy.

Stóg
źródło
Nie działało z akcentowanymi znakami, jak éna przykład (przynajmniej w moim pliku).
Sigur,
1

za pomocą awk:

awk '{print tolower($0)}' file.txt | tee file.txt
Hackaholic
źródło
jesteś pewien, że to zadziała? >file.txtzacznie od obcięcia pliku
iruvar
2
Więc oczywiście nie próbowałeś tego.
Stéphane Chazelas
0

ruby ma do tego metodę łańcuchową, podobne użycie z linii poleceń jak perl

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

Zobacz także kodowanie ruby-doc

$ ruby -e 'puts Encoding.default_external'
UTF-8
$ echo 'αΒγ'  | ruby -pe '$_.swapcase!'
ΑβΓ
Sundeep
źródło
-1

Proste rzeczy proste. Filtr przeznaczony do tłumaczenia znaków to tr.

echo 1ude1UDE | tr [:upper:][:lower:] [:lower:][:upper:]
rogelio
źródło
1
To zepsuta (z powodu brakujących cytatów wokół operatorów globujących) wersja odpowiedzi udzielona już 2 lata wcześniej
Stéphane Chazelas,