Jak przekonwertować pliki UTF-8 txt na wielkie litery w bash?

10

Mam kilka plików .txt UTF-8, które chciałbym przekonwertować na wielkie litery. Gdyby to był tylko ASCII, mógłbym użyć:

tr [:lower:] [:upper:]

Ale ponieważ pracuję z diakrytami i innymi rzeczami, wydaje się, że to nie działa. Myślę, że to może działać, jeśli ustawię odpowiednie ustawienia regionalne, ale potrzebuję tego skryptu, aby był przenośny.

VPeric
źródło

Odpowiedzi:

14

Wszystkie z:

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

(nie zapomnij cytaty, które w przeciwnym razie nie będzie działać, jeśli istnieje plik o nazwie :, l... lub rw bieżącym katalogu) lub:

awk '{print toupper($0)}'

lub:

dd conv=ucase

mają na celu konwersję znaków na wielkie litery zgodnie z regułami określonymi w bieżących ustawieniach regionalnych. Jednak nawet tam, gdzie ustawienia narodowe używają UTF-8 jako zestawu znaków i wyraźnie definiują konwersję małych liter na wielkie, przynajmniej GNU dd, GNU tri mawk(na przykład domyślny awkw Ubuntu) ich nie przestrzegają. Ponadto nie ma standardowego sposobu określania ustawień narodowych innych niż Club POSIX, więc jeśli chcesz konwertować pliki UTF-8 na przenośne wielkie litery niezależnie od bieżących ustawień narodowych, nie masz szczęścia ze standardową skrzynką narzędzi.

Jak często, dla przenośności, najlepszym rozwiązaniem może być Perl:

$ echo lľsšcčtťzž | PERLIO=:utf8 perl -pe '$_=uc'
LĽSŠCČTŤZŽ

Teraz musisz uważać, aby nie wszyscy zgadzali się co do wielkiej wersji określonej postaci.

Na przykład w ustawieniach tureckich wielką literą inie jest I, ale İ( <U0130>). Tutaj z zestawem narzędzi rodowych trzamiast GNU tr:

$ echo ií | LC_ALL=C.UTF-8 tr '[:lower:]' '[:upper:]'
IÍ
$ echo ií | LC_ALL=tr_TR.UTF-8 tr '[:lower:]' '[:upper:]'
İÍ

W moim systemie perlkonwersja na górną jest zdefiniowana w /usr/share/perl/5.14/unicore/To/Upper.pl, i okazuje się, że zachowuje się inaczej na kilku znakach z GNU libc toupper()w C.UTF8lokalizacji, na przykład, perljest bardziej dokładna. Na przykład perlpoprawnie konwertuje ɀ na Ɀ , GNU libc (2.17) tego nie robi.

Stéphane Chazelas
źródło
Jeśli chodzi o jego wartość, pracuję z czeskimi literami (a użyty przykład to w rzeczywistości słowacki), gdzie wszystkie wielkie litery są jasno zdefiniowane, ale zestaw ustawień narodowych prawdopodobnie będzie oznaczony literą C, a nie czeską, więc to jest problem. Perl jest już używany w tym łańcuchu narzędzi, więc dodanie innego użycia może nie być takie złe. Dzięki za szczegółowe wyjaśnienia, btw!
VPeric
3

Myślę, że możesz to zrobić za pomocą awkjego toupperfunkcji.

Na przykład

Nie działa z GNU tr:

$ echo lľsšcčtťzž | tr '[:lower:]' '[:upper:]'
LľSšCčTťZž

Działa z GNU awk:

$ echo lľsšcčtťzž | awk '{ print toupper($0) }'
LĽSŠCČTŤZŽ
slm
źródło
@StephaneChazelas - dzięki, zmieniłem nieudany przykład.
slm
To zależy od aktualnej lokalizacji oraz na trlub awkrealizacji. Na przykład większość trpoprawnie konwertuje znaki w ustawieniach regionalnych UTF8, zgodnie z bieżącymi ustawieniami, GNU trnie. mawknie.
Stéphane Chazelas
1
W rzeczywistości na FreeBSD (9.1) jest odwrotnie. Działa z tr, ale nie zawk
Stéphane Chazelas
@StephaneChazelas - Nie jestem tak zorientowany na wariancje 8-). Ktoś właśnie przegłosował, zastanawiasz się, dlaczego?
slm
2

Działa to z OS X, trale nie z GNU tr:

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

Działa to z, gawkale nie z mawklub nawk(który jest /usr/bin/awkw OS X):

awk '{print toupper($0)}'

Inną opcją jest użycie GNU sed:

sed 's/./\u&/g'

W wersji Bash 4.0 i nowszych możesz również użyć ^^rozszerzenia parametrów:

while IFS= read -r l;do printf %s\\n "${l^^}";done
nisetama
źródło