LINUX.ORG.RU

unicode, сортировка и буква ё


0

0

Почему вот такая штука:

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#ifndef _GNU_SOURCE 
  #define _GNU_SOURCE 
#endif 
#include <wchar.h> 

int compare(const void * ws1, const void * ws2);

int main(void)
{
  wchar_t * ws;

  setlocale(LC_ALL, "");

  ws = wcsdup((wchar_t *)L"аАбБкКёЁеЕфФ");
  if (ws == NULL) exit(1);

  qsort(ws, wcslen(ws), sizeof(wchar_t), compare);
  printf ("ws=[%ls]\n", ws);

  free(ws);

  return 0;
}

int compare(const void * ws1, const void * ws2) {
  return wcscasecmp((wchar_t *)ws1, (wchar_t *)ws2);
}

выдаёт ws=[аАбБЕекКФфЁё] вместо ws=[аАбБеЕёЁкКфФ]?

Точнее:
- почему аА, но Ее?
- почему ё унесло в самый конец?

Дистрибутив Slackware 12.1, локаль ru_RU.utf8.

P.S. Кстати, не могу понять, откуда ругань:
$ gcc -Wall ./sort.c 
./sort.c: В функции ‘main’
./sort.c:18: предупреждение: implicit declaration of function ‘wcsdup’
./sort.c:18: предупреждение: assignment makes pointer from integer without a cast
./sort.c: В функции ‘compare’
./sort.c:30: предупреждение: implicit declaration of function ‘wcscasecmp’
Однако g++ -Wall ./sort.c никаких предупреждений не даёт.

P.P.S. А если использовать диакритические знаки - скажем, крышку над к - то они после сортировки от буквы отрываются. Тоже нехорошо. Ведь наверняка для каких-то алфавитов аналоги нашего ё сделаны в Unicode не одной буквой, а с использованием отдельного диакритического знака.

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

cmp - дурацкое сравнение, основанное на положении таблицы символов.
Сравнение на основе алфавила (LC_LTYPE) - wcscoll.

Кроме того у меня вызывает подозрение Ваша функция сравнения :] (она строки а не символы сравнивает, так надо?)

Хаченный вариант:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#ifndef _GNU_SOURCE
  #define _GNU_SOURCE
#endif
#include <wchar.h>

int compare(const void * ws1, const void * ws2);

int main(void)
{
  setlocale(LC_ALL, "");

  wchar_t * ws = wcsdup((const wchar_t *) L"абвгАБВГедДжЖиИqwertyQWERTYЕйЙёЁ");
  if (!ws) exit(1);

  qsort(ws, wcslen(ws), sizeof(wchar_t), compare);
  printf ("ws=[%ls]\n", ws);

  free(ws);
  return 0;
}

int compare(const void * ws1, const void * ws2) {
  wchar_t w1[2] = { ((const wchar_t *)ws1)[0], 0 };
  wchar_t w2[2] = { ((const wchar_t *)ws2)[0], 0 };
  int r = wcscoll(w1, ws2);
/*
  printf ("cmp: %ls %s %ls\n", w1, r < 0 ? "<"
                                         : r == 0 ? "="
                                         : ">", w2);
*/
  return r;
}


$ ./wcmp 
ws=[eEqQrRtTwWyYаАбБвВгГдДеЕёЁжЖиИйЙ]

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

Спасибо, этот вариант гораздо лучше :-)

Кстати, опечатка:
int r = wcscoll(w1, ws2); -> int r = wcscoll(w1, w2);

А функция сравнения действительно стрёмная получилась. Просто исходной задачей было сравнение строк - вот она так и написалась...

Странно, но у меня в системе почему-то нет man'а на wcscoll.

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

> P.S. Кстати, не могу понять, откуда ругань:
> $ gcc -Wall ./sort.c
> ./sort.c: В функции ‘main’
> ./sort.c:18: предупреждение: implicit declaration of function ‘wcsdup’
> ./sort.c:18: предупреждение: assignment makes pointer from integer without a cast
> ./sort.c: В функции ‘compare’
> ./sort.c:30: предупреждение: implicit declaration of function ‘wcscasecmp’
> Однако g++ -Wall ./sort.c никаких предупреждений не даёт.

Скорее всего в C и C++ хедерах по-разному неявню включается <wchar.h>
Поробуйте определить #define перед всеми хедерами (или в опциях gcc -D).
Такие опции обычно выносят в <config.h> перед всеми стандартными заголовками,
чтобы такого не происходило.

> Кстати, опечатка:
> int r = wcscoll(w1, ws2); -> int r = wcscoll(w1, w2); 
Точно, она самая :]

> Странно, но у меня в системе почему-то нет man'а на wcscoll.
Может, man-pages старый, или не весь (функция, вроде, не из std-c/c++)
equery b wcscoll.3p.bz2
[ Searching for file(s) wcscoll.3p.bz2 in *... ]
sys-apps/man-pages-2.80 (/usr/share/man/man3p/wcscoll.3p.bz2)

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

> Попробуйте определить #define перед всеми хедерами...

Извиняюсь, недопонял :-) Что нужно определить по #define перед каждым стандартным заголовком?

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

> #include <stdio.h> 
> #include <stdlib.h> 
> #include <locale.h> 
> #ifndef _GNU_SOURCE 
>   #define _GNU_SOURCE 
> #endif 
> #include <wchar.h> 

#define _GNU_SOURCE

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <wchar.h> 

sf ★★★
()
Ответ на: комментарий от sergey_feo

>Странно, но у меня в системе почему-то нет man'а на wcscoll.

Аналогично. Нашел в пакете man-pages-posix-2003-a (ALT Linux Sisyphus). На других АЛЬТах можно попробовать поставить man-pages-POSIX. Про другие дистрибутивы не скажу..

php-coder ★★★★★
()
Ответ на: комментарий от php-coder

>#define _GNU_SOURCE
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <locale.h>
>#include <wchar.h>

Да, так не ругается. Помогло :-)

> Нашел в пакете man-pages-posix-2003-a
На http://www.opennet.ru/man.shtml страничка на wcscoll есть в разделах POSIX и Solaris, а в разделе Linux нету.

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