Groß- und Kleinschreibung beachten Groß- / Kleinschreibung comp in C.

74

Ich habe zwei Postleitzahlen char*, die ich vergleichen möchte, ohne die Groß- und Kleinschreibung zu beachten. Gibt es eine Funktion, um dies zu tun?

Oder muss ich bei jeder Verwendung die Tolower-Funktion durchlaufen und dann den Vergleich durchführen?

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

Vielen Dank

bond425
quelle
Ich glaube, ich habe schlecht geschrieben, dass Postleitzahl kein Typ ist, sondern nur der reale Wert, den das Zeichen * haben wird.
Bond425
3
Auf welcher Plattform bist du? Viele Plattformen haben dazu eine plattformspezifische Funktion.
Random832
Wenn Sie eine Zahl mit einem Buchstaben vergleichen, wissen Sie, dass die Zeichenfolgen unabhängig vom Fall nicht gleichwertig sind.
Alex Reynolds
Ich nehme an, Sie meinen nur ASCII-String-Vergleich? Nicht generisch für die ganze Welt in mehreren Regionen?
Doug T.
Der Vergleich könnte zum Vergleich einer Zahl und eines Buchstabens führen. Ich muss testen, ob zwei Postleitzahlen gleich sind, eine größer als oder eine kleiner als. Der größere als, weniger als Teil ist verwirrend, ich bin nicht sicher, wie das funktionieren wird
bond425

Antworten:

66

Im C-Standard gibt es keine Funktion, die dies tut. Unix-Systeme, die POSIX entsprechen, müssen strcasecmpim Header enthalten sein strings.h. Microsoft-Systeme haben stricmp. Um auf der tragbaren Seite zu sein, schreiben Sie Ihre eigenen:

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-Zeichenfolgen funktioniert, nur mit ASCII-Zeichenfolgen.

Fred Foo
quelle
3
Diese Implementierung ist nicht korrekt. es wird fälschlicherweise 0 zurückgeben, wenn b eine Teilzeichenfolge von a ist. Zum Beispiel wird es 0 für strcicmp ("ein anderes", "ein") zurückgeben, aber es sollte 1 zurückgeben
RobertoP
25
Das ist ein schlechter Rat. Es gibt keinen Grund, "eigene" Standard-C-Textfunktionen zu schreiben, um mit einem einfachen Namensunterschied umzugehen. Führen Sie #ifdef _WINDOWS ... #define strcasecmp stricmp ... #endif aus und fügen Sie es in einen entsprechenden Header ein. Die obigen Kommentare, bei denen der Autor die Funktion korrigieren musste, um richtig zu funktionieren, sind der Grund, warum das Umschreiben von Standard-C-Funktionen kontraproduktiv ist, wenn eine weitaus einfachere Lösung verfügbar ist.
B. Nadolson
3
In -std = c ++ 11 ist weder _stricmp noch strcasecmp verfügbar. Sie haben auch unterschiedliche Semantik in Bezug auf das Gebietsschema.
Minexew
2
Dies wird schrecklich brechen, wenn aoder bsind NULL.
YoTengoUnLCD
5
@YoTengoUnLCD Re: schrecklich brechen, wenn a oder b NULL sind . Das Brechen mit aund / oder bwie NULLallgemein üblich als Nullzeiger zeigt nicht auf eine Zeichenfolge . Kein schlechter Scheck zum Hinzufügen, aber was zurückgeben? Sollte cmp("", NULL)0, INT_MIN zurückgeben? Hier besteht kein Konsens. Hinweis: C erlaubt UB mit strcmp(NULL, "abc");.
chux
37

Schauen Sie sich strcasecmp () in an strings.h.

Mihran Hovsepyan
quelle
4
Ich denke du meinst int strcasecmp(const char *s1, const char *s2);in Strings.h
Brigham
2
Diese Funktion ist nicht Standard. Microsoft nennt es stricmp. @entropo: strings.hist ein Header für die Kompatibilität mit Unix-Systemen der 1980er Jahre.
Fred Foo
1
@entropo: Entschuldigung, POSIX scheint zu definieren strings.h. Es wurde auch definiert strcasecmp, in diesem Header deklariert zu werden. ISO C hat es jedoch nicht.
Fred Foo
5
Siehe: Unterschied zwischen String-h und Strings-h . Einige C-Standardbibliotheken haben alle nicht veralteten Funktionen in zusammengeführt string.h. Siehe z. B. Glibc
Entropo
1
@Mihran: Das hat nichts mit dem Compiler zu tun. Es ist ein Bibliotheksproblem.
Fred Foo
7

Ich habe eine eingebaute solche Methode mit dem Namen gefunden, die zusätzliche Zeichenfolgenfunktionen 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 auch festgestellt, dass es ein Synonym im xnu-Kernel (osfmk / device / subrs.c) ist und im folgenden Code implementiert ist, sodass Sie keine Änderung des Verhaltens in Bezug auf die Anzahl im Vergleich zur ursprünglichen strcmp-Funktion erwarten würden.

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));
}
Zohar81
quelle
Ein großes Lob für die Erwähnung der sichereren strncasecmp()Funktion!
Mike C.
strcasecmp()und strncasecmp()sind nicht Teil der Standard-C-Bibliothek, sondern häufige Ergänzungen in * nix.
chux
5

Ich würde verwenden stricmp(). Es werden zwei Zeichenfolgen ohne Rücksicht auf den Fall verglichen.

Beachten Sie, dass in einigen Fällen die Konvertierung der Zeichenfolge in Kleinbuchstaben schneller erfolgen kann.

Jonathan Wood
quelle
4

Zusätzliche Fallstricke, auf die Sie achten müssen, wenn Sie Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung durchführen:


Vergleichen als Klein- oder Großbuchstaben? (häufig genug Problem)

Beide unten geben 0 mit strcicmpL("A", "a")und zurück strcicmpU("A", "a").
Dennoch strcicmpL("A", "_")und strcicmpU("A", "_")können verschiedene signierte Ergebnisse zurück , wie '_'oft zwischen den oberen und Kleinbuchstaben.

Dies wirkt sich bei Verwendung mit auf die Sortierreihenfolge aus qsort(..., ..., ..., strcicmp). Nicht standardmäßige Funktionen der Bibliothek C wie die allgemein verfügbaren stricmp()oder strcasecmp()sind in der Regel gut definiert und begünstigen den Vergleich über 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;
}

charkann einen negativen Wert haben. (nicht selten)

touppper(int)und tolower(int)sind für unsigned charWerte und das Negative angegeben EOF. Ferner strcmp()liefern Ergebnisse , als wenn jede charkonvertierte zu unsigned char, unabhängig davon , ob charsie signiert oder unsigniert .

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

Gebietsschema (seltener)

Obwohl Zeichensätze ASCII Code (0-127) allgegenwärtig sind, neigen die Rest - Codes haben locale spezifische Fragen. Könnte also strcasecmp("\xE4", "a")auf einem System eine 0 und auf einem anderen eine Nicht-Null zurückgeben.


Unicode (der Weg der Zukunft)

Wenn eine Lösung mehr als ASCII verarbeiten muss, ziehen Sie a unicode_strcicmp(). Da C lib eine solche Funktion nicht bietet, wird eine vorcodierte Funktion aus einer alternativen Bibliothek empfohlen. Das eigene zu schreiben unicode_strcicmp()ist eine entmutigende Aufgabe.


Ordnen alle Buchstaben einen unteren einem oberen zu? (pedantisch)

[AZ] ordnet eins zu eins mit [az] zu, doch verschiedene Gebietsschemas ordnen verschiedene Kleinbuchstaben einem Großbuchstaben zu und umgekehrt. Außerdem fehlt einigen Großbuchstaben möglicherweise ein Kleinbuchstabenäquivalent und umgekehrt.

Dies verpflichtet den Code, sowohl tolower()als auch zu verbergen tolower().

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

Auch mögliche unterschiedliche Ergebnisse für die Sortierung , wenn Code tut tolower(toupper(*a))vs. toupper(tolower(*a)).


Portabilität

@B. Nadolson empfiehlt, das Rollen Ihrer eigenen zu vermeiden. strcicmp()Dies ist sinnvoll, es sei denn, Code benötigt eine gleichwertige tragbare Funktionalität.

Im Folgenden finden Sie einen Ansatz, der sogar schneller ausgeführt wird als einige vom System bereitgestellte Funktionen. Es wird ein einzelner Vergleich pro Schleife anstelle von zwei durchgeführt, indem zwei verschiedene Tabellen verwendet werden, die sich von unterscheiden '\0'. 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]);
}
chux - Monica wieder einsetzen
quelle
2

Ich bin nicht wirklich ein Fan der am besten bewerteten Antwort hier (zum Teil, weil es so aussieht, als ob es nicht korrekt ist, da es sollte, continuewenn es einen Null-Terminator in einer der beiden Zeichenfolgen liest - aber nicht in beiden Zeichenfolgen gleichzeitig - und es macht das nicht), also habe ich mein eigenes geschrieben.

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

Es ist identisch mit strncmp()Ausnahme von:

  1. Es wird nicht zwischen Groß- und Kleinschreibung unterschieden.
  2. Das Verhalten ist NICHT undefiniert (es ist gut definiert), wenn eine der Zeichenfolgen null ptr ist. Regular strncmp()hat ein undefiniertes Verhalten, wenn eine der Zeichenfolgen null ptr ist (siehe: https://en.cppreference.com/w/cpp/string/byte/strncmp ).
  3. Es wird INT_MINals spezieller Sentinel-Fehlerwert zurückgegeben, wenn eine der Eingabezeichenfolgen ein NULLptr ist.

EINSCHRÄNKUNGEN: Beachten Sie, dass dieser Code nur mit dem ursprünglichen 7-Bit-ASCII-Zeichensatz (Dezimalwerte 0 bis einschließlich 127) funktioniert , NICHT mit Unicode- Zeichen, wie z. B. Unicode-Zeichencodierungen UTF-8 (am beliebtesten), UTF-16 , und UTF-32 .

Hier ist nur der Code (keine Kommentare):

int strncmpci(const char * str1, const char * str2, size_t num)
{
    int ret_code = 0;
    size_t chars_compared = 0;

    if (!str1 || !str2)
    {
        ret_code = INT_MIN;
        return ret_code;
    }

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

    return ret_code;
}

Vollständig kommentierte Version:

/// \brief      Perform a case-insensitive string compare (`strncmp()` case-insensitive) to see
///             if two C-strings are equal.
/// \note       1. Identical to `strncmp()` except:
///               1. It is case-insensitive.
///               2. The behavior is NOT undefined (it is well-defined) if either string is a null
///               ptr. Regular `strncmp()` has undefined behavior if either string is a null ptr
///               (see: https://en.cppreference.com/w/cpp/string/byte/strncmp).
///               3. It returns `INT_MIN` as a special sentinel value for certain errors.
///             - Posted as an answer here: https://stackoverflow.com/a/55293507/4561887.
///               - Aided/inspired, in part, by `strcicmp()` here:
///                 https://stackoverflow.com/a/5820991/4561887.
/// \param[in]  str1        C string 1 to be compared.
/// \param[in]  str2        C string 2 to be compared.
/// \param[in]  num         max number of chars to compare
/// \return     A comparison code (identical to `strncmp()`, except with the addition
///             of `INT_MIN` as a special sentinel value):
///
///             INT_MIN (usually -2147483648 for int32_t integers)  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.
int strncmpci(const char * str1, const char * str2, size_t num)
{
    int ret_code = 0;
    size_t chars_compared = 0;

    // Check for NULL pointers
    if (!str1 || !str2)
    {
        ret_code = INT_MIN;
        return ret_code;
    }

    // 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++;
    }

    return ret_code;
}

Testcode:

Laden Sie den gesamten Beispielcode mit Komponententests aus meinem eRCaGuy_hello_world- Repository hier herunter : " strncmpci.c" :

(Dies ist nur ein Ausschnitt)

int main()
{
    printf("-----------------------\n"
           "String Comparison Tests\n"
           "-----------------------\n\n");

    int num_failures_expected = 0;

    printf("INTENTIONAL UNIT TEST FAILURE to show what a unit test failure looks like!\n");
    EXPECT_EQUALS(strncmpci("hey", "HEY", 3), 'h' - 'H');
    num_failures_expected++;
    printf("------ beginning ------\n\n");


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

    // NULL ptr checks
    EXPECT_EQUALS(strncmpci(NULL, "", 0), INT_MIN);
    EXPECT_EQUALS(strncmpci("", NULL, 0), INT_MIN);
    EXPECT_EQUALS(strncmpci(NULL, NULL, 0), INT_MIN);
    EXPECT_EQUALS(strncmpci(NULL, "", 10), INT_MIN);
    EXPECT_EQUALS(strncmpci("", NULL, 10), INT_MIN);
    EXPECT_EQUALS(strncmpci(NULL, NULL, 10), INT_MIN);

    EXPECT_EQUALS(strncmpci("", "", 0), 0);
    EXPECT_EQUALS(strncmp("", "", 0), 0);

    str1 = "";
    str2 = "";
    n = 0;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 0);

    str1 = "hey";
    str2 = "HEY";
    n = 0;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 0);

    str1 = "hey";
    str2 = "HEY";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 'h' - 'H');

    str1 = "heY";
    str2 = "HeY";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 'h' - 'H');

    str1 = "hey";
    str2 = "HEdY";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 'y' - 'd');
    EXPECT_EQUALS(strncmp(str1, str2, n), 'h' - 'H');

    str1 = "heY";
    str2 = "hEYd";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 'e' - 'E');

    str1 = "heY";
    str2 = "heyd";
    n = 6;
    EXPECT_EQUALS(strncmpci(str1, str2, n), -'d');
    EXPECT_EQUALS(strncmp(str1, str2, n), 'Y' - 'y');

    str1 = "hey";
    str2 = "hey";
    n = 6;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 0);

    str1 = "hey";
    str2 = "heyd";
    n = 6;
    EXPECT_EQUALS(strncmpci(str1, str2, n), -'d');
    EXPECT_EQUALS(strncmp(str1, str2, n), -'d');

    str1 = "hey";
    str2 = "heyd";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 0);

    str1 = "hEY";
    str2 = "heyYOU";
    n = 3;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 0);
    EXPECT_EQUALS(strncmp(str1, str2, n), 'E' - 'e');

    str1 = "hEY";
    str2 = "heyYOU";
    n = 10;
    EXPECT_EQUALS(strncmpci(str1, str2, n), -'y');
    EXPECT_EQUALS(strncmp(str1, str2, n), 'E' - 'e');

    str1 = "hEYHowAre";
    str2 = "heyYOU";
    n = 10;
    EXPECT_EQUALS(strncmpci(str1, str2, n), 'h' - 'y');
    EXPECT_EQUALS(strncmp(str1, str2, n), 'E' - 'e');

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "NICE TO MEET YOU.,;", 100), 0);
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "NICE TO MEET YOU.,;", 100), 'n' - 'N');
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice to meet you.,;", 100), 0);

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "NICE TO UEET YOU.,;", 100), 'm' - 'u');
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice to uEET YOU.,;", 100), 'm' - 'u');
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice to UEET YOU.,;", 100), 'm' - 'U');

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "NICE TO MEET YOU.,;", 5), 0);
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "NICE TO MEET YOU.,;", 5), 'n' - 'N');

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "NICE eo UEET YOU.,;", 5), 0);
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice eo uEET YOU.,;", 5), 0);

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "NICE eo UEET YOU.,;", 100), 't' - 'e');
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice eo uEET YOU.,;", 100), 't' - 'e');

    EXPECT_EQUALS(strncmpci("nice to meet you.,;", "nice-eo UEET YOU.,;", 5), ' ' - '-');
    EXPECT_EQUALS(strncmp(  "nice to meet you.,;", "nice-eo UEET YOU.,;", 5), ' ' - '-');


    if (globals.error_count == num_failures_expected)
    {
        printf(ANSI_COLOR_GRN "All unit tests passed!" ANSI_COLOR_OFF "\n");
    }
    else
    {
        printf(ANSI_COLOR_RED "FAILED UNIT TESTS! NUMBER OF UNEXPECTED FAILURES = %i"
            ANSI_COLOR_OFF "\n", globals.error_count - num_failures_expected);
    }

    assert(globals.error_count == num_failures_expected);
    return globals.error_count;
}

Beispielausgabe:

$ gcc -Wall -Wextra -Werror -ggdb -std=c11 -o ./bin/tmp strncmpci.c && ./bin/tmp
-----------------------
String Comparison Tests
-----------------------

INTENTIONAL UNIT TEST FAILURE to show what a unit test failure looks like!
FAILED at line 250 in function main! strncmpci("hey", "HEY", 3) != 'h' - 'H'
  a: strncmpci("hey", "HEY", 3) is 0
  b: 'h' - 'H' is 32

------ beginning ------

All unit tests passed!

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

Themen zur weiteren Forschung

  1. (Hinweis: Dies ist C ++, nicht C) Kleinbuchstaben des Unicode-Zeichens
  2. tolower_tests.c in der OnlineGDB: https://onlinegdb.com/HyZieXcew

MACHEN:

  1. Erstellen Sie eine Version dieses Codes, die auch für die UTF-8- Implementierung von Unicode (Zeichencodierung) geeignet ist!
Gabriel Staples
quelle
in part because it isn't correct since ...Ihr Code ist auch nicht korrekt. Es macht keinen Sinn, tolower zu verwenden , es wird bei weitem der langsamste Teil der Funktion sein. Wenn Sie wirklich möchten, dass Ihre Funktion das Gebietsschema kennt und nicht-ASCII-Zeichen verarbeitet, müssen Sie Ihre Zeichen zuerst in nicht signierte Zeichen umwandeln. Andernfalls führt Ihr Code zu UB
Pavel P
@ PavelP, ich folge wirklich nicht dem, was du sagst. Warum macht es keinen Sinn, etwas zu verwenden tolower(), wenn wir auf diese Weise den Effekt erhalten, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Darum geht es bei dieser Frage? Außerdem haben Sie eine Verknüpfung mit der C ++ - Referenz anstelle der C-Referenz erstellt. Ändert das nicht die Dinge? Ich habe nie gesagt, dass meine Funktion das Gebietsschema kennt oder Nicht-ASCII-Zeichen verarbeiten kann, aber ich sehe wirklich nicht, wie das Casting zum unsigned charersten Mal etwas löst. Alle Zeichen können in vorzeichenlose Zeichen umgewandelt werden. Ich verstehe deinen Kommentar nicht.
Gabriel Staples
Ich habe meine Antwort aktualisiert, um anzugeben, dass sie nur für ASCII-Zeichen gilt. Auch wenn Sie eine Antwort schreiben, um zu klären, was Sie meinen, wäre dies hilfreich. Schließlich habe ich kein Nicht-ASCII-Gebietsschema (ich meine kein Nicht- "C"Gebietsschema, das laut setlocale()Standard beim Programmstart ist ) oder Unicode-Erfahrung in C oder C ++. Ich bitte Sie, bei jeder Antwort, die Sie schreiben, gründlich genug zu sein, um diese Punkte und Dinge zu klären.
Gabriel Staples
Nur für ASCII würde ich niemals std :: tolower verwenden, besser manuell : static int tolower(char c){ return (c >= 'A' && c <= 'Z') ? (c | ' ') : c; }. std :: tolower ist sehr langsam, da es das Gebietsschema kennt.
Pavel P
1
Hallo @GaspardP, danke, dass du auf diesen Randfall hingewiesen hast. Ich habe meinen Code jetzt repariert. Das Update war einfach. Ich habe ret_codeauf 0anstatt auf INT_MIN(oder -9999wie in dem von Ihnen getesteten Code) initialisiert und es dann nur auf gesetzt, INT_MINwenn eine der Eingabezeichenfolgen ein NULLptr ist. Jetzt funktioniert es perfekt. Das Problem war einfach, dass für n0 keiner der Blöcke eingegeben wurde (weder der ifnoch der while), also gab es einfach zurück, was ich initialisiert hatte ret_code. Wie auch immer, es ist jetzt behoben und ich habe meine Unit-Tests eine Tonne aufgeräumt und in dem von Ihnen erwähnten Test hinzugefügt. Hoffentlich stimmen Sie jetzt zu.
Gabriel Staples
1

Wie bereits erwähnt, gibt es keine tragbare Funktion, die auf allen Systemen funktioniert. Sie können dies teilweise umgehen, indem Sie einfach ifdef:

#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"));
}
Miljen Mikic
quelle
0

Von hier aus können Sie sich ein Bild davon machen, wie Sie eine effiziente implementieren können, wenn Sie keine in der Bibliothek haben

Es wird eine Tabelle für alle 256 Zeichen verwendet.

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

Dann müssen wir nur noch eine Zeichenfolge 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]);
Andrey Suworow
quelle
0
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

smamran
quelle
1
Die ORIdee ist ein bisschen geschickt, aber die Logik ist fehlerhaft. Zum Beispiel ignoreCaseComp("`", "@", 1)und vielleicht noch wichtiger ignoreCaseComp("\0", " ", 1)(dh wenn alle anderen Bits als Bit 5 (Dezimal 32) identisch sind) werden beide als 0(Übereinstimmung) ausgewertet .
user966939
0

Einfache Lösung:

int str_case_ins_cmp(const char* a, const char* b) {
  int rc;

  while (1) {
    rc = tolower((unsigned char)*a) - tolower((unsigned char)*b);
    if (rc || !*a) {
      break;
    }

    ++a;
    ++b;
  }

  return rc;
}
Ericcurtin
quelle
-1
int strcmpInsensitive(char* a, char* b)
{
    return strcmp(lowerCaseWord(a), lowerCaseWord(b));
}

char* lowerCaseWord(char* a)
{
    char *b=new char[strlen(a)];
    for (int i = 0; i < strlen(a); i++)
    {
        b[i] = tolower(a[i]);   
    }
    return b;
}

Viel Glück

Die Funktion Edit-lowerCaseWord ruft eine char * -Variable mit ab und gibt den Kleinbuchstabenwert dieses char * zurück. Beispiel: "AbCdE" für den Wert von char * gibt "abcde" zurück.

Grundsätzlich werden die beiden char * -Variablen nach der Übertragung in Kleinbuchstaben verwendet und die strcmp-Funktion für sie verwendet.

Wenn wir beispielsweise die Funktion strcmpInsensitive für Werte von "AbCdE" und "ABCDE" aufrufen, werden zuerst beide Werte in Kleinbuchstaben ("abcde") zurückgegeben und anschließend die Funktion strcmp ausgeführt.

Jaldk
quelle
Einige Erklärungen könnten einen langen Weg gehen
Davejal
Es scheint völlig ineffizient zu sein, beide Eingabezeichenfolgen zu senken, wenn die Funktion "möglicherweise" zurückkehrt, sobald stattdessen das erste Zeichen verglichen wird. Beispiel: "ABcDe" vs "BcdEF" kann sehr schnell zurückkehren, ohne dass etwas anderes als das erste Zeichen jeder Zeichenfolge gesenkt oder angehoben werden muss.
TS
4
Ganz zu schweigen von zweimaligem Speicherverlust.
Ruud van Gaal
Sie beenden Ihre Kleinbuchstaben nicht mit Null, sodass das nachfolgende Zeichenfolgenprogramm strcmp()möglicherweise abstürzt.
etw
Sie berechnen auch strlen (a) insgesamt strlen (a) +1 mal. Das zusammen mit der Schleife selbst und Sie durchlaufen eine strlen (a) +2 mal.
Stefan Vorkoetter