Является ли LC_ALL=C деструктивным?

Является ли LC_ALL=C деструктивным?

У меня есть довольно большой (~15 ГБ) набор текстовых файлов. Эти файлы по сути являются простыми базами данных, содержащими учетные данные, и учетные данные в них часто выходят за пределы 128-символьного диапазона ASCII (символы с ударениями и т. п.).

Когда я пытаюсь отсортировать некоторые из этих файлов с помощью:

sort -u input.txt -o output.txt

...Я получаю следующую ошибку:

sort: string comparison failed: Invalid or incomplete multibyte or wide character
sort: Set LC_ALL='C' to work around the problem.

Я много читал о том, как использование LC_ALL=Cможет ускорить команды, которые работают с символами, такими как sortи grep, включаяБлестящий ответ Стефана Шазеласапо этой теме, но меня особенно беспокоят последствия его использования в моем наборе данных.

Вероятно ли, что запуск LC_ALL=C sort -uэтих файлов приведет к удалению из них каких-либо символов, не входящих в набор ASCII?

Если это, то что я могу сделать вместо этого, чтобы исправить/удалить все "недействительные или неполные многобайтовые или широкие символы" из этих файлов, что позволяет мне сортировать их без использования LC_ALL=C?

решение1

Приведет ли выполнение команды LC_ALL=C sort -u к удалению из этих файлов любых символов, не входящих в набор ASCII?

В данном случае нет, нет — sortон будет работать непосредственно со значениями байтов, а не пытаться преобразовать их в символы.

Однако то же самое не обязательно применимо к другим инструментам. Программы, написанные на языке C (язык), с наибольшей вероятностью будут вести себя таким образом. Программы, написанные на языках с сильным различием байтов и символов, например, на Python 3, должны полностью отказаться принимать ввод, который не соответствует набору символов. И я, конечно, могу представить себе плохо написанные программы, которые игнорируют ошибки и выводят � или ?вместо этого.

Если это так, то что я могу сделать вместо этого, чтобы исправить/удалить все «недопустимые или неполные многобайтовые или широкие символы» из этих файлов, что позволит мне сортировать их без использования LC_ALL=C?

Убедитесь, что все они используют одну и ту же кодировку файла (предпочтительно UTF-8), и что ваша локаль использует ту же кодировку. Ошибка никогда не должна возникать для допустимого файла UTF-8, независимо от его размера.

решение2

Поскольку в итоге мне пришлось пропускать свои файлы через множество различных инструментов Bash, таких как sort, grep, awk, wcи tr, я решил, что безопаснее будет воспользоваться "правильным решением", указанным в принятом ответе; сначала преобразовать их все в UTF-8. Это оказалось немного сложнее, чем я ожидал, не в последнюю очередь потому, что мне потребовалось некоторое время, чтобы понять, что fileэто ненадежный способ определения того, является ли файл ASCII или UTF-8 (потому что он не проверяет весь файл), поэтому я размещаю этот ответ здесь для потомков.

Чтобы окончательно определить, в какой кодировке находятся ваши файлы, сначала убедитесь, что uchardetпакет установлен с помощью установщика Cygwin илиapt-cyg, затем запустите:

uchardet *.txt

Или, если вы не используете Cygwin:

chardet *.txt 

chardetПереместите все перечисленные файлы ASCIIв отдельную папку и выполните forв этой папке следующий цикл:

for i in *.txt; do iconv -f ASCII -t UTF-8 "$i" >> "${i%.txt}_utf.txt"; done;

Он пройдёт по всем .txtфайлам в папке и создаст их версии UTF-8 с utfдобавленным суффиксом.

Повторный запуск uchardet *.txtможет по-прежнему отображать некоторые файлы как ASCII. Это происходит потому, что ASCII является подмножеством UTF-8, ипросто означаетчто эти файлы не содержат символов, выходящих за пределы диапазона ASCII в 128 бит.

Теперь вы сможете работать sortбез необходимости использования LC_ALL=C.

Связанный контент