7

私は完全に同意しない理由で、「(反ユーザビリティの)その力」は私の反対にもかかわらず引き続き命令します。私は基本的な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);

どうすればいいのかを考えるのに少し時間がかかるかもしれませんが、リリース直前のスペック変更で頭がおかしくなったのは私だけではないと思います。

4

6 に答える 6

16

必要なことは、各キャラクターの順序表を作成することです。これは、大文字と小文字を区別しない比較を行う最も簡単な方法でもあります。

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);
于 2010-06-15T21:30:23.977 に答える
8

あなたの能力が私が遭遇した他のすべての能力と同じである場合は、それをオプションにすることができます(たとえそれが隠されていても):

ソート順:

o 文字の後の数字

o 数字の後の文字

さらに悪いことに、数値を数値順に並べ替えたい (たとえば、"A123" が"A15" の後に来る) ことに気付くかもしれません。

o 文字の後の数字

o 数字の後の文字

o 文字の後のスマート番号

o スマート番号の後の文字

これは、症状ではなく、実際の問題を診断することになります。11 時間 59 分で気が変わる可能性がわずかにあるに違いありません。

于 2010-06-15T22:12:51.293 に答える
5

文字を比較するときに、ルックアップテーブルを使用してASCIIをEBCDICに変換できます;-)

于 2010-06-15T21:20:31.733 に答える
4

この特殊なケースでは、大文字 (コメントの 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);
}

もちろん、オーダー テーブル ソリューションは、すべての文字の並べ替え順序を定義できるため、一般的にはるかに汎用性があります。このソリューションは、大文字と数字の特殊なケースにのみ適しています。(ただし、たとえばマイクロコントローラ プラットフォームでは、テーブルが使用する少量のメモリを節約することで、実際にメリットが得られる場合があります。)

于 2010-06-16T01:22:43.253 に答える
3

上記の回答に概ね同意していますが、ほとんどの比較で最初の文字が異なると思われる場合を除き、ループの反復ごとにルックアップを行うのはばかげていると思います。

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

また、静的初期化子を使用して order_table を作成することをお勧めします。これにより、速度が向上し (毎回生成する必要がなくなります)、おそらく読みやすさも向上します。

于 2010-06-15T22:31:07.117 に答える
2

これは、他の投稿で説明されているものと同様の文字列比較のかなり良い実装になるはずです。

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);
于 2010-06-15T22:16:56.567 に答える