Як довести до відома не-ascii (unicode) символів?


36

Я намагаюся видалити деякі символи з файлу (UTF-8). Я використовую trдля цієї мети:

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

Файл містить деякі іноземні символи (наприклад, "Латвійська" або "àé"). trСхоже, їх не розуміє: він трактує їх як не-альфа і видаляє теж.

Я спробував змінити деякі мої параметри локалі:

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

На жаль, жодне з них не спрацювало.

Як я можу trзрозуміти Unicode?

Відповіді:


29

Це відоме ( 1 , 2 , 3 , 4 , 5 , 6 ) обмеження реалізації GNU tr.

Справа не стільки в тому, що він не підтримує іноземні , не англійські або не ASCII символи, але і не підтримує багатобайтові символи.

Ці кириличні символи вважатимуться нормально, якщо вони написані в наборі символів iso8859-5 (однобайтовий на кожний символ) (і ваша локаль використовувала цю схему), але ваша проблема полягає в тому, що ви використовуєте UTF-8 там, де не ASCII символи кодуються в 2 або більше байтів.

GNU має план (див. Також ), щоб виправити це, і робота ведеться, але ще не існує.

У FreeBSD або Solaris trпроблем немає.


Тим часом, для більшості випадків використання trви можете використовувати GNU sed або GNU awk, які підтримують багатобайтові символи.

Наприклад, ваші:

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

можна було написати:

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

або:

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

Для перетворення між малим і великим регістром ( tr '[:upper:]' '[:lower:]'):

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

(тобто lмалі L, а не 1цифри).

або:

gawk '{print tolower($0)}'

Щодо мобільності - perlце ще одна альтернатива:

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

Якщо ви знаєте, що дані можуть бути представлені в однобайтовому наборі символів, ви можете обробити їх у цій діаграмі:

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

1
Я прийняв ваше запитання через інформацію про тр. Я вирішив проблему і видалив питання, як її вирішити (тому люди, які шукають tr, знайдуть лише інформацію про tr, а не якусь довільну проблему). Якщо ви можете також видалити рішення, оскільки воно більше не потрібно, я буду вдячний.
MatthewRock

3
@MatthewRock Я зберігав це, але переробив його і зробив більш загальним, оскільки слово навколо було б корисно людям з тією ж проблемою.
Стефан Шазелас

Звідки ви розумієте, що кирилиця (звичайно) закодована в ISO 8859-5? Ви ніколи не бачили російського тексту в чому-небудь, крім Unicode?
Incnis Mrsi

9
@IncnisMrsi, все, що тут важливо, - це те, що ISO 8859-5 є одним із тих сингетних байтів, які мають ці кириличні символи. Незалежно від того, широко використовується він чи ні, тут не має значення. Якщо у вас є локаль з KOI-R або charset-1251, обов'язково використовуйте його.
Stéphane Chazelas

@IncnisMrsi Російська мова в Інтернеті майже завжди кодується в UTF-8 (або періодично в Windows-1251), але лише тому, що ми відчували біль багатьох однобайтових кодувань на початку. Ось старовинна (близько 1998 р.) Веб-сторінка з (нефункціональним) перемикачем кодування: sch57.ru/collect .
Олексій Шпількін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.