Jak uświadomić TR, że znaki nie są ascii (Unicode)?


36

Próbuję usunąć niektóre znaki z pliku (UTF-8). Używam trdo tego celu:

tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat 

Plik zawiera niektóre obce znaki (np. „Латвийская” lub „àé”). trwydaje się ich nie rozumieć: traktuje je jako inne niż alfa i również je usuwa.

Próbowałem zmienić niektóre ustawienia regionalne:

LC_CTYPE=C LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat

Niestety żaden z nich nie zadziałał.

Jak mogę trzrozumieć Unicode?

Odpowiedzi:


29

Jest to znane ( 1 , 2 , 3 , 4 , 5 , 6 ) ograniczenie implementacji GNU tr.

Nie chodzi o to, że nie obsługuje znaków obcych , nieanglojęzycznych ani ASCII, ale nie obsługuje znaków wielobajtowych.

Te znaki cyrylicy byłyby traktowane OK, gdyby zostały zapisane w zestawie znaków iso8859-5 (jednobajtowy na znak) (a twoje ustawienia regionalne używały tego zestawu znaków), ale twoim problemem jest to, że używasz UTF-8, gdy nie jest to ASCII znaki są zakodowane w 2 lub więcej bajtach.

GNU ma plan (patrz także ), aby to naprawić, a prace są w toku, ale jeszcze ich nie ma.

FreeBSD lub Solaris trnie mają problemu.


Tymczasem dla większości przypadków użycia trmożesz użyć GNU sed lub GNU awk, które obsługują znaki wielobajtowe.

Na przykład:

tr -cs '[[:alpha:][:space:]]' ' '

można napisać:

gsed -E 's/( |[^[:space:][:alpha:]])+/ /'

lub:

gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'

Aby przekonwertować małe i wielkie litery ( tr '[:upper:]' '[:lower:]'):

gsed 's/[[:upper:]]/\l&/g'

(to ljest mała litera L, a nie 1cyfra).

lub:

gawk '{print tolower($0)}'

Przenośność perlto kolejna alternatywa:

perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'

Jeśli wiesz, że dane mogą być reprezentowane w jednobajtowym zestawie znaków, możesz przetworzyć je w tym zestawie znaków:

(export LC_ALL=ru_RU.iso88595
 iconv -f utf-8 |
   tr -cs '[:alpha:][:space:]' ' ' |
   iconv -t utf-8) < Russian-file.utf8

1
Zaakceptowałem twoje pytanie z powodu informacji o tr. Rozwiązałem problem i usunąłem pytanie o to, jak go rozwiązać (więc ludzie szukający tr znajdą tylko informacje o tr, a nie jakiś arbitralny problem). Jeśli mógłbyś również usunąć rozwiązanie, ponieważ nie jest ono już potrzebne, byłbym wdzięczny.
MatthewRock,

3
@MatthewRock Zachowałem go, ale przeredagowałem i uczyniłem bardziej ogólnym, ponieważ podanie słowa byłoby przydatne dla osób z tym samym problemem.
Stéphane Chazelas,

Skąd pomysł, że Cyrylica jest (zwyczajowo) zakodowana w ISO 8859-5? Czy widziałeś kiedyś rosyjski tekst w innym miejscu niż Unicode?
Incnis Mrsi

9
@IncnisMrsi, liczy się tylko to, że ISO 8859-5 jest jednym z tych pojedynczych zestawów znaków, które mają te znaki cyrylicy. Nie ma znaczenia, czy jest w powszechnym użyciu, czy nie. Jeśli masz ustawienia regionalne z zestawem znaków KOI-R lub Window-1251, z pewnością skorzystaj z niego.
Stéphane Chazelas,

@IncnisMrsi Rosyjski w sieci jest prawie zawsze kodowany w UTF-8 (lub czasami w Windows-1251), ale tylko dlatego, że wcześnie odczuliśmy ból wielu kodowań jednobajtowych. Oto starożytna (około 1998 r.) Strona internetowa z (niefunkcjonalnym) przełącznikiem kodowania: sch57.ru/collect .
Alex Shpilkin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.