По причинам я полностью не соглашаюсь с, но "Полномочия (Антиудобства использования), Что Быть" продолжают устанавливать декретом несмотря на мои возражения, у меня есть программа сортировки, которая делает основной 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);
Я предполагаю, что, возможно, должен был бы не торопиться далеко для реального размышления о том, как это должно быть сделано, но я уверен, что я не единственный, кто испытал мозговую монотонность изменений спецификации непосредственно-перед-тем,-как-выпуска.
В этом особом случае с только заглавными буквами (как указано 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 Конечно, решение таблицы порядка в целом гораздо более универсально, поскольку оно позволяет определять порядок сортировки для каждого символа - это решение разумно только для этого особого случая с прописными буквами и цифрами. (Но, например, на платформах микроконтроллеров экономия даже небольшого количества памяти, используемой таблицей, может быть реальным преимуществом.)
Что вам нужно нужно создать таблицу заказа для каждого персонажа. Это также самый простой способ сравнения без учета регистра.
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);
Если ваши власть имущие похожи на всех других власть имущих, с которыми я сталкивался, вы можете сделать опцию (даже если она скрыта):
Порядок сортировки:
o Числа после букв
o Буквы после чисел
или, что еще хуже, они могут понять, что хотят, чтобы Числа сортировались по числам (например. например, "A123" идет после "A15"), тогда это может быть
o Цифры после букв
o Буквы после цифр
o Умные цифры после букв
o Буквы после умных цифр
Это уже диагностика реальной проблемы, а не симптома. Держу пари, есть небольшой шанс, что они передумают на 11-м часу и 59-й минуте.
Вы можете использовать таблицу поиска для преобразования ASCII в EBCDIC при сравнении символов; -)
Хотя в целом согласен с приведенными выше ответами, я думаю, что глупо выполнять поиск для каждой итерации цикла, если вы не думаете, что большинство сравнений будут иметь разные первые символы, когда вы могли бы вместо этого сделайте
char c1, c2;
while((c1 = *(s1++)) == (c2 = *(s2++)) && c1 != '\0');
return order_table[c1] - order_table[c2];
Кроме того, я бы порекомендовал создать таблицу order_table со статическим инициализатором, который улучшит скорость (нет необходимости генерировать каждый раз - или когда-либо), а также, возможно, удобочитаемость
Вот что должно быть довольно хорошей реализацией сравнения строк, подобной той, что описана в других постах.
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);