C中的Case Insensitive String comp

bon*_*425 63 c string standard-library

我有两个char*我要比较的邮政编码,忽略了大小写.有这个功能吗?

或者我是否必须遍历每个使用tolower函数然后进行比较?

知道这个函数如何对字符串中的数字做出反应

谢谢

Fre*_*Foo 60

在C标准中没有这样做的功能.符合POSIX的Unix系统需要strcasecmp在标题中strings.h; 微软系统有stricmp.要在便携式方面,写下你自己的:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但请注意,这些解决方案都不适用于UTF-8字符串,只能使用ASCII字符串.

  • 这是一个糟糕的建议.没有理由"编写自己的"标准C文本函数来处理简单的名称差异.#ifdef _WINDOWS ... #define strcasecmp stricmp ... #endif并将其放在合适的标题中.上述注释中作者必须将函数修复为正常工作,这就是为什么如果有一个更简单的解决方案,重写标准C函数会适得其反. (21认同)
  • @YoTengoUnLCD 回复:[当 a 或 b 为 NULL 时会崩溃](/sf/ask/407456731/#comment81529857_5820991)。将 `a` 和/或 `b` 拆分为 `NULL` 是普遍接受的做法,因为 _null 指针_不指向 _string_。添加不错的支票,但要返回什么?`cmp("", NULL)` 应该返回 0, INT_MIN 吗?对此没有达成共识。注意:C 允许带有 `strcmp(NULL, "abc");` 的 UB。 (7认同)
  • 这种实现不正确; 当b是a的子字符串时,它将错误地返回0.例如,它将为strcicmp("另一个","an")返回0,但它应返回1 (3认同)
  • 在-std = c ++ 11中,_stricmp和strcasecmp都不可用.它们在语言环境方面也有不同的语义. (3认同)
  • 当a或b为NULL时,这将彻底中断。 (2认同)

Mih*_*yan 36

看看到strcasecmp()strings.h.

  • 我认为你的意思是`int strcasecmp(const char*s1,const char*s2);`in strings.h (4认同)
  • 请参阅:[string-h-and-strings-h之间的差异](http://stackoverflow.com/questions/4291149/difference-between-string-h-and-strings-h/4291328#4291328).一些C标准库已将所有未弃用的函数合并到`string.h`中.参见,例如,[Glibc](http://www.gnu.org/software/libc/manual/html_mono/libc.html#String_002fArray-Comparison) (4认同)
  • 此功能是非标准的;微软称它为“ stricmp”。@entropo:strings.h是与1980年代Unix系统兼容的头文件。 (2认同)

chu*_*ica 6

进行不区分大小写的比较时要注意的其他陷阱:


比较小写还是大写?(足够常见的问题)

下面两个都将返回 0strcicmpL("A", "a")strcicmpU("A", "a")
然而,strcicmpL("A", "_")andstrcicmpU("A", "_")可以返回不同的签名结果,'_'通常在大写和小写字母之间。

这会影响与 一起使用时的排序顺序qsort(..., ..., ..., strcicmp)。非标准库 C 函数,如常用的 stricmp()strcasecmp()倾向于定义良好的函数,并且倾向于通过小写字母进行比较。然而,变化是存在的。

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

int strcicmpU(char const *a, char const *b) {
  while (*b) {
    int d = toupper(*a) - toupper(*b);
    if (d) {
        return d;
    } 
    a++;
    b++;
  } 
  return toupper(*a);
}
Run Code Online (Sandbox Code Playgroud)

char可以有负值。(并不罕见)

touppper(int)tolower(int)unsigned charvalues 和负数指定EOF。此外,strcmp()返回结果就像每个都char被转换为unsigned char,无论charsigned还是unsigned

tolower(*a); // Potential UB
tolower((unsigned char) *a); // Correct (Almost - see following)
Run Code Online (Sandbox Code Playgroud)

char可以有一个负值而不是 2 的补码。(稀有的)

由于-0位模式应解释为unsigned char. 要正确处理所有整数编码,请先更改指针类型。

// tolower((unsigned char) *a);
tolower(*(const unsigned char *)a); // Correct
Run Code Online (Sandbox Code Playgroud)

语言环境(不太常见)

尽管使用 ASCII 代码 (0-127) 的字符集无处不在,但其余代码往往具有特定于语言环境的问题。所以strcasecmp("\xE4", "a")可能在一个系统上返回 0,在另一个系统上返回非零。


Unicode(未来的方式)

如果解决方案需要处理的不仅仅是 ASCII,请考虑使用unicode_strcicmp(). 由于 C lib 不提供这样的函数,因此建议使用某个替代库中的预编码函数。编写自己的代码 unicode_strcicmp()是一项艰巨的任务。


所有字母都从低到高映射吗?(迂腐)

[AZ] 与 [az] 一对一映射,但各种语言环境将各种小写字符映射到一个大写字符,反之亦然。此外,某些大写字符可能缺少等效的小写字符,反之亦然。

这迫使代码通过tolower()和 进行转换tolower()

int d = tolower(toupper(*a)) - tolower(toupper(*b));
Run Code Online (Sandbox Code Playgroud)

同样,如果代码tolower(toupper(*a))toupper(tolower(*a)).


可移植性

@B。Nadolson建议避免自己滚动strcicmp(),这是合理的,除非代码需要高度等效的可移植功能。

下面是一种甚至比某些系统提供的函数执行得更快的方法。它通过使用 2 个不同的表对每个循环进行一次比较而不是两次比较'\0'。您的结果可能会有所不同。

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[*(const unsigned char *)a] == low2[*(const unsigned char *)b]) {
    a++;
    b++;
  }
  // Either strings differ or null character detected.
  // Perform subtraction using same table.
  return (low1[*(const unsigned char *)a] - low1[*(const unsigned char *)b]);
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*ood 5

我会用stricmp()。它比较两个字符串而不考虑大小写。

请注意,在某些情况下,将字符串转换为小写可能会更快。


Zoh*_*r81 5

我发现内置的这样的方法名为from,其中包含标准标头中的其他字符串函数。

这是相关的签名:

int  strcasecmp(const char *, const char *);
int  strncasecmp(const char *, const char *, size_t);
Run Code Online (Sandbox Code Playgroud)

我还发现它是xnu内核(osfmk / device / subrs.c)的同义词,并在以下代码中实现,因此与原始的strcmp函数相比,您不会期望其行为发生任何变化。

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));
}
Run Code Online (Sandbox Code Playgroud)