strcmp (), но с 0-9 ПОСЛЕ A-Z? (C/C++)

По причинам я полностью не соглашаюсь с, но "Полномочия (Антиудобства использования), Что Быть" продолжают устанавливать декретом несмотря на мои возражения, у меня есть программа сортировки, которая делает основной strcmp (), выдерживает сравнение с видом его именем. Это работает отлично; трудно понять превратно то. Однако в 11-й час, было решено, чтобы записи, которые начинаются с числа, произошли ПОСЛЕ записей, которые начинаются с буквы вопреки упорядочиванию ASCII. Они цитируют стандарт EBCDIC, имеет числа после букв, таким образом, предшествующее предположение не является универсальной истиной, и я не имею никакого права выигрывать этот спор..., но я отступаю.

Там находится моя проблема. Я заменил все соответствующие ссылки на strcmp с новым вызовом функции nonstd_strcmp и теперь должен реализовать модификации для выполнения изменения вида. Я использовал источник FreeBSD в качестве своей базы: http://freebsd.active-venture.com/FreeBSD-srctree/newsrc/libkern/strncmp.c.html

 if (n == 0)
  return (0);
 do {
  if (*s1 != *s2++)
   return (*(const unsigned char *)s1 -
    *(const unsigned char *)(s2 - 1));
  if (*s1++ == 0)
   break;
 } while (--n != 0);
 return (0);

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

7
задан Aaron Burke 15 June 2010 в 21:18
поделиться

6 ответов

В этом особом случае с только заглавными буквами (как указано OP в комментариях) и цифрами 0–9, вы также можете опустить таблицу порядка и вместо этого умножить оба разных символа на 4 и сравнить результаты по модулю 256. Диапазон цифр ASCII (от 48 до 57) не будет превышать 8 бит (57 × 4 = 228), но диапазон прописных букв (от 65 до 90) будет (65 × 4 = 260). Когда мы сравниваем умноженные значения по модулю 256, значение для каждой буквы будет меньше, чем у любой цифры: 90 × 4% 256 = 104 <192 = 48 × 4

Код может выглядеть примерно так:

int my_strcmp (const char *s1, const char *s2) {
    for (; *s1 == *s2 && *s1; ++s1, ++s2);
    return (((*(const unsigned char *)s1) * 4) & 0xFF) - \
           (((*(const unsigned char *)s2) * 4) & 0xFF);
}

Of Конечно, решение таблицы порядка в целом гораздо более универсально, поскольку оно позволяет определять порядок сортировки для каждого символа - это решение разумно только для этого особого случая с прописными буквами и цифрами. (Но, например, на платформах микроконтроллеров экономия даже небольшого количества памяти, используемой таблицей, может быть реальным преимуществом.)

4
ответ дан 6 December 2019 в 05:08
поделиться

Что вам нужно нужно создать таблицу заказа для каждого персонажа. Это также самый простой способ сравнения без учета регистра.

if (order_table[*s1] != order_table[*s2++])

Имейте в виду, что символы могут быть подписаны, и в этом случае индекс вашей таблицы может стать отрицательным. Этот код предназначен только для символов со знаком:

int raw_order_table[256];
int * order_table = raw_order_table + 128;
for (int i = -128;  i < 128;  ++i)
    order_table[i] = (i >= '0' && i <= '9') ? i + 256 : toupper(i);
16
ответ дан 6 December 2019 в 05:08
поделиться

Если ваши власть имущие похожи на всех других власть имущих, с которыми я сталкивался, вы можете сделать опцию (даже если она скрыта):

Порядок сортировки:

o Числа после букв

o Буквы после чисел

или, что еще хуже, они могут понять, что хотят, чтобы Числа сортировались по числам (например. например, "A123" идет после "A15"), тогда это может быть

o Цифры после букв

o Буквы после цифр

o Умные цифры после букв

o Буквы после умных цифр

Это уже диагностика реальной проблемы, а не симптома. Держу пари, есть небольшой шанс, что они передумают на 11-м часу и 59-й минуте.

8
ответ дан 6 December 2019 в 05:08
поделиться

Вы можете использовать таблицу поиска для преобразования ASCII в EBCDIC при сравнении символов; -)

5
ответ дан 6 December 2019 в 05:08
поделиться

Хотя в целом согласен с приведенными выше ответами, я думаю, что глупо выполнять поиск для каждой итерации цикла, если вы не думаете, что большинство сравнений будут иметь разные первые символы, когда вы могли бы вместо этого сделайте

char c1, c2;
while((c1 = *(s1++)) == (c2 = *(s2++)) && c1 != '\0');
return order_table[c1] - order_table[c2];

Кроме того, я бы порекомендовал создать таблицу order_table со статическим инициализатором, который улучшит скорость (нет необходимости генерировать каждый раз - или когда-либо), а также, возможно, удобочитаемость

3
ответ дан 6 December 2019 в 05:08
поделиться

Вот что должно быть довольно хорошей реализацией сравнения строк, подобной той, что описана в других постах.

static const unsigned char char_remap_table[256] = /* values */

#define char_remap(c) (char_remap_table[(unsigned char) c])

int nonstd_strcmp(const char * restrict A, const char * restrict B) {
     while (1) {
          char a = *A++;
          char b = *B++;
          int x = char_remap(a) - char_remap(b);
          if (x) {
               return x;
          }
          /* Still using null termination, so test that from the original char,
           * but if \0 maps to \0 or you want to use a different end of string
           * then you could use the remapped version, which would probably work
           * a little better b/c the compiler wouldn't have to keep the original
           * var a around. */
          if (!a) { /* You already know b == a here, so only one test is needed */
               return x;  /* x is already 0 and returning it allows the compiler to
                           * store it in the register that it would store function
                           * return values in without doing any extra moves. */
          }
     }
}

Помимо этого, вы могли бы обобщить функцию, чтобы она принимала char_remap_table в качестве параметра, что позволило бы вам легко использовать различные отображения позже, если вам это понадобится.

int nonstd_strcmp(const char * restrict a, const char * restrict b, const char * restrict map);
2
ответ дан 6 December 2019 в 05:08
поделиться