LINUX.ORG.RU

LC_COLLATE и gnu sort

 ,


0

1

Привет!

Как такое может быть:

$ LC_COLLATE="C.UTF-8" echo -e "1\t-----------$\n2\tOTHER\n3\t-а$" | LC_COLLATE="C.UTF-8" sort -k2,2 -t $'\t'
1       -----------$
3       -а$
2       OTHER
$ LC_COLLATE="en_US.utf8" echo -e "1\t-----------$\n2\tOTHER\n3\t-а$" | LC_COLLATE="en_US.utf8" sort -k2,2 -t $'\t'
1       -----------$
2       OTHER
3       -а$

Как в стандартной локали en_US.utf8 слово OTHER может оказаться между двумя словами, начинающимися с минусов ? -а$ содержит русскую букву а. если a английское, то все ОК,

Если это объяснимо свойствами локали, то нафиг такую локаль, посоветуйте любую юникодную без фокусов.

sort -k2,2 -t $'\t'

Сперва объясни, что это значит. Потом можно перейти к локалям.

anonymous
()
Ответ на: комментарий от anonymous

Это сортировка строк из STDIN по второму полю, разделитель табуляция.

Я уже само вижу баг - локаль неправильно названа в моем примере, должно быть LC_COLLATE=«en_US.UTF-8», и с ней в примере проблемы не возникает. Но написал я не на пустом месте - у меня стоит

declare -x LANG="en_US.UTF-8"

и на большом файле я вижу это:


$ echo -e "1\t-----------$\n2\tOTHER\n3\t-а$" | sort -k2,2  -t $'\t'
1       -----------$
2       OTHER
3       -а$


anymouse
() автор топика
Ответ на: комментарий от anymouse

Вот чистый пример, который непонятен:

$ LC_COLLATE="en_US.UTF-8" | echo -e "-----------$\nOTHER\n-а$" | sort
-----------$
OTHER
-а$

Что бы я не ставил вместо LC_COLLATE=«en_US.UTF-8», порядок сортированных записей получается такой же.

Где собака порылась ?

anymouse
() автор топика
Ответ на: комментарий от anymouse

То есть блин да, настройку окружения ставим для программы sort:

так правильно сортирует:

echo -e "-----------$\nOTHER\n-а$" | LC_COLLATE="C.UTF-8" sort

так неправильно:

echo -e "-----------$\nOTHER\n-а$" | LC_COLLATE="en_US.UTF-8" sort
anymouse
() автор топика
Ответ на: комментарий от anymouse
sort -k2,2

Я всех тонкостей работы с полями не помню, ты уверен что не сортируешь по второму символу второго поля? Отсортируй список с одним столбцом без магии с полями.

anonymous
()
Ответ на: комментарий от anymouse
"-----------$\nOTHER\n-а$"

«a» - латинская или русская? Если русская, никто из американцев тебе ничего не обязан.

anonymous
()
Ответ на: комментарий от anonymous

Русская. Нет, дело не в этом. Я считаю, что если локаль отмечена как UTF-8 то она может по-разному определять порядок для юникодных символов, но какой-то порядок есть и он определен строго, а тут получается, что есть пример, где порядок нарушается.

Нагуглил ответ на серверфолте, там похожая проблема, и все символы в примере это минус и латинские маленькие.

anymouse
() автор топика
Ответ на: комментарий от anonymous

И вот пожалуйста, сгенерировал русскую локаль:

echo -e "-----------$\nOTHER\n-а$" | LC_COLLATE="ru_RU.UTF-8" sort

Порядок тот же - OTHER в середине.

anymouse
() автор топика
Ответ на: комментарий от anymouse

Похожая проблема с японским:

$ cat file
イグネイシャス
アンダートン
ウッドフォックス
エナルズ
ムスヒ
オフサイト
コラクル
ベントグラス
ギタウ
テンター
$ LANG="en_US.UTF-8" sort -u file
ムスヒ
エナルズ
オフサイト
アンダートン
イグネイシャス
ウッドフォックス

сортировка оставляет 6 записей, при том, что во входном файле все записи уникальны.

Наверное остановлюсь на LANG=C, или LANG=C.UTF-8

Спасибо за внимание :-)

anymouse
() автор топика

Набросал простенькую программу

#include <string.h>
#include <locale.h>
int main(int argc, char* argv[]) {
  setlocale(LC_ALL, "");
  int x = strcoll(argv[1], argv[2]);
  return (x < 0) ? -1 : (x > 0);
}
Подтверждаю, сравнение строк в утф локалях забагованное

anonymous
()
Ответ на: комментарий от anonymous

Не забагованно, почитайте уже на пару с ТС'ом про collate, что это такое и как оно работает.

anonymous
()
Ответ на: комментарий от anonymous

почитайте уже на пару с ТС'ом про collate

Прочитал. Написал еще одну маленькую программу с strxfrm:

#include <string.h>
#include <locale.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
  char out[1024];
  setlocale(LC_ALL, "");
  strxfrm(out, argv[1], 1024);
  fprintf(stderr, "%s\n", argv[1]);
  printf("%s\n", out);
  for(char* p = out; *p; p++) {
    unsigned int c = (unsigned char)*p;
    printf("%02x ", c);
  }
  puts("");
  return 0;
}
Посмотрел, что он творит со утф-строками содержащими вполне легальные символы -_! и тп. Могу сказать, это нельзя использовать для лексикографического сравнения строк. Баг или фича в данном случае - это чисто индивидуальная эмоциональная оценка.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.