webentwicklung-frage-antwort-db.com.de

Groß- und Kleinschreibung wird in C nicht berücksichtigt

Ich habe zwei Postleitzahlen char*, die ich vergleichen möchte, und ignoriere dabei den Fall .

Oder muss ich durchlaufen, die Tolower-Funktion verwenden und dann den Vergleich durchführen?

Jede Idee, wie diese Funktion mit Zahlen in der Zeichenfolge reagiert

Vielen Dank

52
bond425

Es gibt keine Funktion, die dies im C-Standard tut. Unix-Systeme, die POSIX erfüllen, müssen strcasecmp im Header strings.h; Microsoft-Systeme haben stricmp. Schreiben Sie Ihre eigene:

int strcicmp(char const *a, char const *b)
{
    for (;; a++, b++) {
        int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
        if (d != 0 || !*a)
            return d;
    }
}

Beachten Sie jedoch, dass keine dieser Lösungen mit UTF-8-Strings funktioniert, nur mit ASCII.

54
Fred Foo

Schau nach strcasecmp () in strings.h.

28

Ich würde stricmp() verwenden. Es vergleicht zwei Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung.

Beachten Sie, dass das Konvertieren der Zeichenfolge in Kleinbuchstaben in manchen Fällen schneller sein kann.

4
Jonathan Wood

Ich habe eine eingebaute Methode gefunden, deren Name zusätzliche String-Funktionen zum Standardheader enthält. 

Hier sind die relevanten Unterschriften: 

int  strcasecmp(const char *, const char *);
int  strncasecmp(const char *, const char *, size_t);

Ich habe es auch im Xnu-Kernel (osfmk/device/subrs.c) als Synonym gefunden und im folgenden Code implementiert, so dass Sie nicht erwarten würden, dass sich die Anzahl im Vergleich zur ursprünglichen strcmp-Funktion ändert. 

tolower(unsigned char ch) {
    if (ch >= 'A' && ch <= 'Z')
        ch = 'a' + (ch - 'A');
    return ch;
 }

int strcasecmp(const char *s1, const char *s2) {
    const unsigned char *us1 = (const u_char *)s1,
                        *us2 = (const u_char *)s2;

    while (tolower(*us1) == tolower(*us2++))
        if (*us1++ == '\0')
            return (0);
    return (tolower(*us1) - tolower(*--us2));
}
4
Zohar81

Zusätzliche Fallstricke, auf die Sie achten sollten, wenn Sie die Groß-/Kleinschreibung beachten:


Vergleich als Kleinschreibung oder als Großschreibung? (Häufig genug)}

Beide unten geben 0 mit strcicmpL("A", "a") und strcicmpU("A", "a") zurück.
Dennoch können strcicmpL("A", "_") und strcicmpU("A", "_") unterschiedliche signierte Ergebnisse zurückgeben, da '_' häufig zwischen Groß- und Kleinbuchstaben steht. 

Dies beeinflusst die Sortierreihenfolge bei Verwendung mit qsort(..., ..., ..., strcicmp). Nicht standardmäßige Bibliotheks-C-Funktionen wie die allgemein verfügbaren stricmp() oder strcasecmp() sind in der Regel gut definiert und bevorzugen den Vergleich mit Kleinbuchstaben. Es gibt jedoch Variationen.

int strcicmpL(char const *a, char const *b) {
  while (*a) {
    int d = tolower(*a) - tolower(*b);
    if (d) {
        return d;
    } 
    a++;
    b++;
  } 
  return 0;
}

int strcicmpU(char const *a, char const *b) {
  while (*a) {
    int d = toupper(*a) - toupper(*b);
    if (d) {
        return d;
    } 
    a++;
    b++;
  } 
  return 0;
}

char kann einen negativen Wert haben. (nicht selten)

touppper(int) und tolower(int) werden für unsigned char-Werte und die negative EOF angegeben. strcmp() gibt Ergebnisse zurück, als ob jede char in unsigned char konvertiert wurde, unabhängig davon, ob charsigniert oder unsigned ist.

tolower(*a); // Potential UB
tolower((unsigned char) *a); // Correct

Gebietsschema (weniger verbreitet)

Obwohl Zeichensätze, die den ASCII - Code (0-127) verwenden, allgegenwärtig sind, neigen die übrigen Codes dazu, locale spezifische Probleme zu haben. Daher kann strcasecmp("\xE4", "a") in einem System eine 0 und in einem anderen nicht null zurückgeben.


Unicode (der Weg der Zukunft)

Wenn eine Lösung mehr als ASCII verarbeiten muss, beachten Sie eine unicode_strcicmp(). Da C lib keine solche Funktion bereitstellt, wird eine vorcodierte Funktion aus einer alternativen Bibliothek empfohlen. Das Schreiben Ihrer eigenen unicode_strcicmp() ist eine entmutigende Aufgabe.


Sind alle Buchstaben um eins höher als eins? (Pedantisch)}

[A-Z] kartiert Eins-zu-Eins mit [a-z], aber verschiedene -Locales kartieren verschiedene Kleinschreibungstypen zu einem oberen und umgekehrt. Bei einigen Großbuchstaben kann es auch zu Kleinbuchstaben und umgekehrt kommen.

Dies zwingt den Code dazu, über tolower() und tolower() zu verbergen.

int d = tolower(toupper(*a)) - tolower(toupper(*b));

Möglicherweise unterschiedliche Ergebnisse für die Sortierung, wenn der Code tolower(toupper(*a)) vs. toupper(tolower(*a)) war.


Portabilität

@B. Nadolson empfiehlt, das Rollen Ihrer eigenen strcicmp() zu vermeiden, und dies ist sinnvoll, es sei denn, Code erfordert eine gleichwertige tragbare Funktionalität.

Nachfolgend wird ein Ansatz beschrieben, der sogar schneller als einige vom System bereitgestellte Funktionen ausgeführt wird. Es führt einen einzigen Vergleich pro Schleife durch, anstatt zwei, indem zwei verschiedene Tabellen verwendet werden, die sich mit '\0' unterscheiden. Ihre Ergebnisse können variieren.

static unsigned char low1[UCHAR_MAX + 1] = {
  0, 1, 2, 3, ...
  '@', 'a', 'b', 'c', ... 'z', `[`, ...  // @ABC... Z[...
  '`', 'a', 'b', 'c', ... 'z', `{`, ...  // `abc... z{...
}
static unsigned char low2[UCHAR_MAX + 1] = {
// v--- Not zero, but A which matches none in `low1[]`
  'A', 1, 2, 3, ...
  '@', 'a', 'b', 'c', ... 'z', `[`, ...
  '`', 'a', 'b', 'c', ... 'z', `{`, ...
}

int strcicmp_ch(char const *a, char const *b) {
  // compare using tables that differ slightly.
  while (low1[(unsigned char)*a] == low2[(unsigned char)*b]) {
    a++;
    b++;
  }
  // Either strings differ or null character detected.
  // Perform subtraction using same table.
  return (low1[(unsigned char)*a] - low1[(unsigned char)*b]);
}
1
chux
static int ignoreCaseComp (const char *str1, const char *str2, int length)
{
    int k;
    for (k = 0; k < length; k++)
    {

        if ((str1[k] | 32) != (str2[k] | 32))
            break;
    }

    if (k != length)
        return 1;
    return 0;
}

Referenz

1
S. M. AMRAN

Eine Vorstellung davon, wie Sie eine effiziente implementieren können, wenn Sie noch keine in der Bibliothek haben, können Sie unter hier

Es verwendet eine Tabelle für alle 256 Zeichen. 

  • in dieser Tabelle für alle Zeichen außer Buchstaben wurden die ASCII-Codes verwendet. 
  • für Großbuchstabencodes - die Tabellenlistencodes der Symbole in Kleinbuchstaben. 

dann müssen wir nur eine Zeichenkette durchlaufen und unsere Tabellenzellen für bestimmte Zeichen vergleichen:

const char *cm = charmap,
        *us1 = (const char *)s1,
        *us2 = (const char *)s2;
while (cm[*us1] == cm[*us2++])
    if (*us1++ == '\0')
        return (0);
return (cm[*us1] - cm[*--us2]);
0
Andrey Suvorov

Ich bin nicht wirklich ein Fan der hier am häufigsten gestellten Antwort (zum Teil, weil sie nicht korrekt ist, da sie fortgesetzt werden sollte, wenn ein Nullterminator in einer der beiden Zeichenfolgen gelesen wird - aber nicht in beiden Zeichenfolgen gleichzeitig - und das tut es nicht), also habe ich mein eigenes geschrieben.

Dies ist ein direkter Ersatz für strncmp() und wurde mit zahlreichen Testfällen vollständig getestet, wie unten gezeigt:

Nur der Code:

#include <ctype.h> // for `tolower()`
#include <limits.h> // for `INT_MIN`

// Case-insensitive `strncmp()`
static inline int strncmpci(const char * str1, const char * str2, size_t num)
{
    int ret_code = INT_MIN;
    size_t chars_compared = 0;

    if (!str1 || !str2)
    {
        goto done;
    }

    while ((*str1 || *str2) && (chars_compared < num))
    {
        ret_code = tolower((int)(*str1)) - tolower((int)(*str2));
        if (ret_code != 0)
        {
            break;
        }
        chars_compared++;
        str1++;
        str2++;
    }

done:
    return ret_code;
}

Vollkommentierte Version:

#include <ctype.h> // for `tolower()`
#include <limits.h> // for `INT_MIN`

/*

Case-insensitive string compare (strncmp case-insensitive)
- Identical to strncmp except case-insensitive. See: http://www.cplusplus.com/reference/cstring/strncmp/
- Aided/inspired, in part, by: https://stackoverflow.com/a/5820991/4561887

str1    C string 1 to be compared
str2    C string 2 to be compared
num     max number of chars to compare

return:
(essentially identical to strncmp)
INT_MIN  invalid arguments (one or both of the input strings is a NULL pointer)
<0       the first character that does not match has a lower value in str1 than in str2
 0       the contents of both strings are equal
>0       the first character that does not match has a greater value in str1 than in str2

*/
static inline int strncmpci(const char * str1, const char * str2, size_t num)
{
    int ret_code = INT_MIN;

    size_t chars_compared = 0;

    // Check for NULL pointers
    if (!str1 || !str2)
    {
        goto done;
    }

    // Continue doing case-insensitive comparisons, one-character-at-a-time, of str1 to str2, 
    // as long as at least one of the strings still has more characters in it, and we have
    // not yet compared num chars.
    while ((*str1 || *str2) && (chars_compared < num))
    {
        ret_code = tolower((int)(*str1)) - tolower((int)(*str2));
        if (ret_code != 0)
        {
            // The 2 chars just compared don't match
            break;
        }
        chars_compared++;
        str1++;
        str2++;
    }

done:
    return ret_code;
}

Testcode: (hier online ausführen): https://onlinegdb.com/B1Qoj0W_N

int main()
{
    printf("Hello World\n\n");

    const char * str1;
    const char * str2;
    size_t n;

    str1 = "hey";
    str2 = "HEY";
    n = 3;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "heY";
    str2 = "HeY";
    n = 3;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "hey";
    str2 = "HEdY";
    n = 3;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "heY";
    str2 = "HeYd";
    n = 3;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));   
    printf("\n");

    str1 = "heY";
    str2 = "HeYd";
    n = 6;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "hey";
    str2 = "hey";
    n = 6;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "hey";
    str2 = "heyd";
    n = 6;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    str1 = "hey";
    str2 = "heyd";
    n = 3;
    printf("strncmpci(%s, %s, %u) = %i\n", str1, str2, n, strncmpci(str1, str2, n));
    printf("strncmp(%s, %s, %u) = %i\n", str1, str2, n, strncmp(str1, str2, n));
    printf("\n");

    return 0;
}

Beispielausgabe:

Hallo Welt

strncmpci (hey, HEY, 3) = 0
strncmp (hey, HEY, 3) = 32

strncmpci (heY, HeY, 3) = 0
strncmp (heY, HeY, 3) = 32

strncmpci (hey, HEdY, 3) = 21
strncmp (hey, HEdY, 3) = 32

strncmpci (heY, HeYd, 3) = 0
strncmp (heY, HeYd, 3) = 32

strncmpci (heY, HeYd, 6) = -100
strncmp (heY, HeYd, 6) = 32

strncmpci (hey, hey, 6) = 0
[...] strncmp (hey, hey, 6) = 0

strncmpci (hey, heyd, 6) = -100
[...] strncmp (hey, heyd, 6) = -100

strncmpci (hey, heyd, 3) = 0
[...] strncmp (hey, heyd, 3) = 0

Verweise:

  1. Diese Frage und andere Antworten hier dienten als Inspiration und gaben einen Einblick ( Case Insensitive String comp in C )
  2. http://www.cplusplus.com/reference/cstring/strncmp/
  3. https://en.wikipedia.org/wiki/ASCII
  4. https://en.cppreference.com/w/c/language/operator_precedence
0
Gabriel Staples

Wie andere angegeben haben, gibt es keine tragbare Funktion, die auf allen Systemen funktioniert. Sie können dies mit einfachem ifdef teilweise umgehen:

#include <stdio.h>

#ifdef _WIN32
#include <string.h>
#define strcasecmp _stricmp
#else // assuming POSIX or BSD compliant system
#include <strings.h>
#endif

int main() {
    printf("%d", strcasecmp("teSt", "TEst"));
}
0
Miljen Mikic