Domanda

Per ragioni che completamente d'accordo con Ma "The Powers (su Anti-usabilità) che essere" continuano a decreto nonostante le mie obiezioni, ho una routine di ordinamento che fa strcmp di base () confronta per ordinare con il suo nome. E le grandi opere; è difficile ottenere che quella sbagliata. Tuttavia, alla ore 11, è stato deciso che le voci che iniziano con un numero veniva dopo le voci che iniziano con una lettera, in contrasto con l'ordinamento ASCII. Citano lo standard EBCDIC ha numeri seguenti lettere così l'ipotesi precedente non è una verità universale, e non ho alcun potere di vincere questa tesi ... ma sto divagando.

Qui sta il mio problema. Ho sostituito tutti i riferimenti adeguati a strcmp con una nuova funzione chiamata nonstd_strcmp, e ora hanno bisogno di attuare le modifiche per realizzare il cambiamento sorta. Ho usato una fonte di FreeBSD come la mia base: 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);

Credo di aver bisogno di prendere un po 'di tempo lontano per davvero pensare a come dovrebbe essere fatto, ma sono sicuro che io non sono l'unico che ha sperimentato il cervello morto il just-prima-release modifiche spec.

È stato utile?

Soluzione

In questo caso speciale con solo maiuscole lettere (come indicato dal PO nei commenti) e le cifre 0-9, si potrebbe anche omettere il tavolo ordine e invece si moltiplicano entrambi i personaggi differenti da 4 e confrontare i risultati modulo 256. la gamma di cifre ASCII (da 48 a 57) non sarà in overflow 8 bit (57 × 4 = 228), ma l'intervallo di lettere maiuscole (da 65 a 90) sarà (65 × 4 = 260). Quando si confrontano i valori moltiplicati modulo 256, il valore di ogni lettera sarà inferiore a quella di qualsiasi cifra: 90 × 4% 256 = 104 <192 = 48 × 4

Il codice potrebbe essere simile:

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);
}

Naturalmente, la soluzione tavolo ordine è molto più versatile in generale in quanto permette di definire un ordinamento per ogni carattere questa soluzione è ragionevole solo per questo caso particolare con maiuscolo lettere vs cifre . (Ma per esempio su piattaforme microcontrollori, risparmiando anche la piccola quantità di memoria utilizzata dal tavolo può essere un vero beneficio.)

Altri suggerimenti

Quello che dovete fare è creare una tabella di ordinamento per ogni personaggio. Questo è anche il modo più semplice per fare i confronti case-insensitive pure.

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

Essere consapevoli del fatto che i caratteri potrebbero essere firmati, nel qual caso l'indice al vostro tavolo potrebbe andare negativo. Questo codice è per caratteri firmati solo:

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);

Se i tuoi poteri-che-essere sono come tutti gli altri poteri-che-essere che ho incontrato, si può decidere di renderlo un'opzione (anche se è nascosto):

  

Ordine:

     

o I numeri dopo le lettere

     

o lettere dopo i numeri

o, peggio ancora, si potrebbe capire che vogliono i numeri per essere ordinati numericamente (per esempio "A123" deriva dopo "A15"), allora può essere

  

o I numeri dopo le lettere

     

o lettere dopo i numeri

     

o Numbers intelligenti dopo Letters

     

o lettere dopo i numeri intelligente

Questo entra nel diagnosticare il vero problema, non il sintomo. Scommetto che c'è una piccola possibilità che possono cambiare la loro mente al 11 ° ora e 59 ° minuto.

Si potrebbe utilizzare una tabella di ricerca di tradurre ASCII a EBCDIC quando si confrontano i personaggi; -)

Mentre in accordo con le risposte di cui sopra, penso che sia sciocco fare ricerche per ogni iterazione del ciclo, a meno che non si pensa che la maggior parte i confronti avranno diversi primi caratteri, quando si potrebbe invece fare

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

Inoltre, mi sento di raccomandare la costruzione del order_table con un inizializzatore statico, che migliorerà la velocità (non c'è bisogno di generare ogni volta - o mai) e forse anche la leggibilità

Ecco quello che dovrebbe essere un'implementazione abbastanza buona della stringa confronta simile a quello descritto da altri messaggi.

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. */
          }
     }
}

Al di là che si potrebbe generalizzare la funzione per prendere il char_remap_table come un parametro che permetterebbe di usare facilmente diverse mappature in seguito, se avevi bisogno di.

int nonstd_strcmp(const char * restrict a, const char * restrict b, const char * restrict map);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top