2つの郵便番号char*
大文字と小文字を区別せずに比較したい。これを行う機能はありますか?
または、tolower関数を使用するたびにループしてから比較を行う必要がありますか?
この関数が文字列内の数値とどのように反応するかについての考え
ありがとう
C標準にはこれを行う機能はありません。 POSIXに準拠するUnixシステムでは、ヘッダーに strcasecmp
が必要ですstrings.h
; Microsoftシステムには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;
}
}
ただし、これらのソリューションはいずれもUTF-8ストリングでは機能せず、ASCIIの1つのみです。
strings.h
の strcasecmp() を見てください。
stricmp()
を使用します。大文字小文字を区別せずに2つの文字列を比較します。
場合によっては、文字列を小文字に変換する方が高速になる場合があることに注意してください。
標準ヘッダーに追加の文字列関数を含むfromという名前の組み込みメソッドが見つかりました。
関連する署名は次のとおりです。
int strcasecmp(const char *, const char *);
int strncasecmp(const char *, const char *, size_t);
また、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));
}
小文字と大文字の比較? (十分に一般的な問題)
以下の両方は、strcicmpL("A", "a")
とstrcicmpU("A", "a")
で0を返します。
まだstrcicmpL("A", "_")
とstrcicmpU("A", "_")
は、'_'
が大文字と小文字の間にあることが多いため、異なる署名結果を返すことができます。
これは、qsort(..., ..., ..., strcicmp)
で使用される場合のソート順に影響します。一般的に利用可能なstricmp()
やstrcasecmp()
のような非標準ライブラリC関数は、明確に定義される傾向があり、小文字での比較に適しています。まだバリエーションがあります。
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
には負の値を指定できます。 (まれではない)
touppper(int)
とtolower(int)
は、unsigned char
値と負のEOF
に対して指定されます。さらに、strcmp()
は、char
がsignedまたはであるかどうかに関係なく、各char
がunsigned char
に変換されたかのように結果を返します。符号なし。
tolower(*a); // Potential UB
tolower((unsigned char) *a); // Correct
ロケール(あまり一般的ではない)
ASCIIコード(0-127)を使用した文字セットはいたるところにありますが、残りのコードにはlocale特定の問題がある傾向があります。したがって、strcasecmp("\xE4", "a")
は1つのシステムでは0で、別のシステムではゼロ以外です。
Unicode(未来の道)
ソリューションがASCII以上を処理する必要がある場合、unicode_strcicmp()
を検討してください。Clibはそのような関数を提供しないため、代替ライブラリの事前コード化関数が推奨されます。独自のunicode_strcicmp()
は困難な作業です。
すべての文字は下から上にマッピングされますか? (pedantic)
[A-Z]は[a-z]で1対1にマッピングしますが、さまざまなlocalesさまざまな小文字の文字を1つの大文字にマッピングします。さらに、一部の大文字には、同等の小文字、さらにはビザが欠けている場合があります。
これにより、コードはtolower()
とtolower()
の両方を変換する必要があります。
int d = tolower(toupper(*a)) - tolower(toupper(*b));
繰り返しますが、コードがtolower(toupper(*a))
とtoupper(tolower(*a))
を実行した場合、ソートの結果が異なる可能性があります。
移植性
@ B。Nadolson 独自のstrcicmp()
のロールを避けることをお勧めします。これは、コードに高度な同等のポータブル機能が必要な場合を除き、合理的です。
以下は、システムが提供する機能よりも高速に実行されるアプローチです。 '\0'
と異なる2つの異なるテーブルを使用して、2つではなくループごとに1つの比較を行います。結果は異なる場合があります。
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]);
}
ライブラリに何もなければ、効率的なものを実装する方法のアイデアを得ることができます here
256文字すべてのテーブルを使用します。
次に、文字列をトラバースし、指定された文字のテーブルセルを比較するだけです。
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]);
私は実際には ここで最も支持されている答え の一部ではありません一度-そしてそれはこれを行いません)、私は自分で書いた。
strncmp()
の直接ドロップイン置換であり、以下に示すように、多数のテストケースで完全にテストされています。コードのみ:
#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;
}
完全コメント版:
#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;
}
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;
}
こんにちは世界
strncmpci(hey、HEY、3)= 0
strncmp(hey、HEY、3)= 32strncmpci(heY、HeY、3)= 0
strncmp(heY、HeY、3)= 32strncmpci(hey、HEdY、3)= 21
strncmp(hey、HEdY、3)= 32strncmpci(heY、HeYd、3)= 0
strncmp(heY、HeYd、3)= 32strncmpci(heY、HeYd、6)= -100
strncmp(heY、HeYd、6)= 32strncmpci(hey、hey、6)= 0
strncmp(hey、hey、6)= 0strncmpci(hey、heyd、6)= -100
strncmp(hey、heyd、6)= -100strncmpci(hey、heyd、3)= 0
strncmp(hey、heyd、3)= 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;
}
他の人が述べたように、すべてのシステムで機能する移植可能な機能はありません。単純な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"));
}