Сравнение символьных строк

Сравнение символьных строк [Вперед] [Вверх] [Назад] [Содержание]
Дальше: Интернационализация сообщений Вверх: Интернационализация Назад: Форматирование чисел и дежежных

Сравнение символьных строк

Для лексикографического сравнения символьных строк с учетом установленного locale используются фунцкии strcoll и strxfrm. На работу этих фунцкий оказывает влияние значение категории LC_COLLATE. Для их использования необходимо подключать заголовочный файл string.h.

Функция strcoll объявлена следующим образом:

int strcoll(const char *s1, const char *s2);
и возвращает значения:
  • 0, если символьные строки равны;
  • > 0, если строка s1 ``больше'' (``позже'') s2 в соответствии с порядком букв в национальном алфавите, и
  • < 0, если строка s1 ``меньше'' (``раньше'') s2.
Если текущее locale есть locale по умолчанию, то вызов функции strcoll эквивалентен вызову функции strcmp.

Для описания функции strxfrm необходимо дать некоторые пояснения. Дело в том, что функция strcoll при сравнении строк переводит их в некоторое промежуточное представление в соответствии с текущим locale, и сравнение происходит не самих строк непосредственно, а этих промежуточных представлений. Функция strcoll деляет такое преобразование всегда и неявно. Функция strxfrm делает это преобразование явно, давая возможность пользователю получить промежуточное представление непосредственно. Эта возможность предусмотрена для тех ситуаций, когда сравнение небольшого количества одних и тех же строк производится многократно. Здесь рекомендуется получить промежуточные представления всех строк, а затем сравнивать уже эти промежуточные преставления непосредственно функцией strcmp -- результат будет тот же самый, что и при сравнении самих строк функцией strcoll.

Функция strxfrm объявлена следующим образом:

size_t strxfrm(char *dest, const char *src, size_t n);
Выполняется преобразование строки str, первые n символов результата записываются в dest и возвращается количество байт, требуемых для сохранения результата (завершающий строку символ с кодом 0 не учитывается). Если возвращенное значение больше n, содержимое dest не определено.

Ниже приведен пример использования функций strcoll и strxfrm:

/*
 * strings.c
 * Использование функций strcoll и strxfrm.
 */

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

#ifdef _GNU_SOURCE
extern char *program_invocation_short_name;
#else
const char *program_name;
#define program_invocation_short_name program_name
#endif /* _GNU_SOURCE */

typedef struct {
  char *string;              /* Символьная строка */
  char *string_internal_rep; /* Внутреннее представление, 
                                создаваемое функцией strxfrm */
  int data;
  /* ... еще много чего */
} some_data;

some_data some_array[] = {
  {"это", NULL, 1},
  {"массив", NULL, 2}, 
  {"строк", NULL, 3},
  {"который", NULL, 4},
  {"должен", NULL, 5},
  {"быть", NULL, 6},
  {"отсортирован", NULL, 7},
  {"правильно", NULL, 8}};

void init_internal_reps (void) {
  some_data *dp;
  char strbuf[256];
  
  for (dp = some_array; 
       dp < some_array + sizeof(some_array)/sizeof(some_data); 
       dp++) {
    strxfrm (strbuf, dp->string, strlen (dp->string));
    if (!(dp->string_internal_rep = strdup (strbuf))) {
      fprintf (stderr, "%s: failed to duplicate string `%s'\n",
               program_invocation_short_name, 
               dp->string_internal_rep);
      exit (1);
    }
  }
}

void print_result (char *about_message) {
  some_data *dp;
  printf ("%s\n", about_message);
  for (dp = some_array; 
       dp < some_array + sizeof(some_array)/sizeof(some_data); 
       dp++)
    printf ("{%s, %d}\n", dp->string, dp->data);
}
  
int cmp_by_string (const void *p, const void *q) {
  return strcoll (((some_data *)p)->string, 
                  ((some_data *)q)->string);
}

int cmp_by_internal_rep (const void *p, const void *q) {
  return strcmp (((some_data *)p)->string_internal_rep, 
                 ((some_data *)q)->string_internal_rep);
}

int cmp_to_restore_original_order (const void *p, const void *q) {
  return ((some_data *)p)->data - ((some_data *)q)->data;
}

int main (int argc, char *argv[]) {
#ifndef _GNU_SOURCE
  program_name = argv[0];
#endif

  print_result ("Before sorting:");
  init_internal_reps ();
  
  if (!setlocale (LC_COLLATE, "ru_SU")) {
    fprintf (stderr, "%s: failed to set locale\n",
             program_invocation_short_name);
    exit (1);
  }

  qsort (some_array, sizeof(some_array)/sizeof(some_data),
         sizeof(some_data), cmp_by_string);
  print_result ("After sorting by strings:");
  
  qsort (some_array, sizeof(some_array)/sizeof(some_data),
         sizeof(some_data), cmp_to_restore_original_order);
  print_result ("After restoring original order:");

  qsort (some_array, sizeof(some_array)/sizeof(some_data),
         sizeof(some_data), cmp_by_internal_rep);
  print_result ("After sorting by internal representation:");

  return 0;
}

Компилировать эту программу нужно примерно так же, как и предыдущий пример.



Dmitry A. Antipov
1999-05-26