C语⾔字母排序不分⼤⼩写,如何按字母顺序排序字符串数组(区分⼤⼩写,⾮标准排序规则)...
保持⼀致的话⼀起…
对于单词列表,将“相同”的单词组合在⼀起(即使情况不同)往往更为有⽤.例如:
Keeping things together: Simple "M after m":
------------------------ -------------------
mars mars
mars bar mars bar
Mars bar milk
milk milk-duds
Milk milky-way
milk-duds Mars bar
milky-way Milk
Milky-way Milky-way
如果你想要排列第⼀列的单词,我会提出三种⽅式:
>使⽤strcasecmp()结合strcmp().
>使⽤isalpha(),tolower()和isupper()跟踪字符类型的单次执⾏实现.
>使⽤整理表的单次执⾏.
最后我讨论了两个选择:
>使⽤整理表建⽴任意排序.
>设置区域设置以使⽤基于区域设置的整理.
使⽤可⽤的库函数
如果可以这样做,请避免重新发明车轮.在这种情况下,我们可以通过使⽤POSIX函数strcasecmp()来查看它们是否与不区分⼤⼩写的⽐较相等,并在它们之后退回到strcmp().
int alphaBetize (const char *a, const char *b) {
int r = strcasecmp(a, b);
if (r) return r;
/* if equal ignoring case, use opposite of strcmp() result to get
* lower before upper */
return -strcmp(a, b); /* aka: return strcmp(b, a); */
}
(在某些系统上,不区分⼤⼩写的⽐较函数称为stricmp()或_stricmp(),如果您不可⽤,则在下⾯提供⼀个实现)
#ifdef I_DONT_HAVE_STRCASECMP
int strcasecmp (const char *a, const char *b) {
while (*a && *b) {
if (tolower(*a) != tolower(*b)) {
break;
}
++a;
++b;
}
return tolower(*a) - tolower(*b);
}
#endif
避免两次通过字符串
有时,现有的功能表现不够好,你必须做别的事情才能使事情更快.以下功能在单次传递中以⼤致相同的⽅式进⾏⽐较,⽽不使⽤strcasecmp()或strcmp().但是,它将所有⾮字母字符视为⼩于字母.
int alphaBetize (const char *a, const char *b) {
int weight = 0;
isalpha 函数
do {
if (*a != *b) {
if (!(isalpha(*a) && isalpha(*b))) {
if (isalpha(*a) || isalpha(*b)) {
return isalpha(*a) - isalpha(*b);
}
return *a - *b;
}
if (tolower(*a) != tolower(*b)) {
return tolower(*a) - tolower(*b);
}
/* treat as equal, but mark the weight if not set */
if (weight == 0) {
weight = isupper(*a) - isupper(*b);
}
}
++a;
++b;
} while (*a && *b);
/* if the words compared equal, use the weight as tie breaker */
if (*a == *b) {
return weight;
}
return !*b - !*a;
}
使⽤这种⽐较进⾏排序将保持⽜奶和⽜奶相邻,即使列表包括⽜奶.
使⽤整理表
这是⼀种从“配置”动态创建整理表的⽅法.它⽤于说明⼀种对⽐技术来改变字符串的⽐较.
您可以映射字母表中的字母与⼀种简单的表格,描述您想要的字母(或NUL字节之外的任何字符)的相对顺序:
const char * alphaBetical =
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
从这个顺序,我们可以创建⼀个查表,看看两个字母应该相互⽐较.以下函数初始化表,如果还没有⾸先完成,否则执⾏表查. int alphaBeta_lookup (int c) {
static int initialized;
static char table[CHAR_MAX+1];
if (!initialized) {
/* leave all non-alphaBeticals in their relative order, but below
alphaBeticals */
int i, j;
for (i = j = 1; i < CHAR_MAX+1; ++i) {
if (strchr(alphaBetical, i)) continue;
table[i] = j++;
}
/* now run through the alphaBeticals */
for (i = 0; alphaBetical[i]; ++i) {
table[(int)alphaBetical[i]] = j++;
}
initialized = 1;
}
/* return the computed ordinal of the provided character */
if (c < 0 || c > CHAR_MAX) return c;
return table[c];
}
使⽤这个查表,我们现在可以简化alphaBetize()⽐较函数的循环体:
int alphaBetize (const char *a, const char *b) {
int ax = alphaBeta_lookup(*a);
int bx = alphaBeta_lookup(*b);
int weight = 0;
do {
char al = tolower(*a);
char bl = tolower(*b);
if (ax != bx) {
if (al != bl) {
return alphaBeta_lookup(al) - alphaBeta_lookup(bl);
}
if (weight == 0) {
weight = ax - bx;
}
}
ax = alphaBeta_lookup(*++a);
bx = alphaBeta_lookup(*++b);
} while (ax && bx);
/* if the words compared equal, use the weight as tie breaker */
return (ax != bx) ? !bx - !ax : weight;
}
我们可以让事情更简单吗?
使⽤整理表,您可以使⽤简化的⽐较功能创建许多不同的排序,如:
int simple_collating (const char *a, const char *b) {
while (alphaBeta_lookup(*a) == alphaBeta_lookup(*b)) {
if (*a == '\0') break;
++a, ++b;
}
return alphaBeta_lookup(*a) - alphaBeta_lookup(*b);
}
使⽤这个相同的功能,通过修改alphaBetical字符串,你可以实现⼏乎任何你想要的排序(按字母顺序排列,按字母顺序排列,辅⾳前的元⾳等).然⽽,保持⼀致的单词的安排需要散布⼤写字母的⼩写字母,这只能通过做⼀个⽐较忽略的情况来完成.
请注意,使⽤上⾯的simple_collat i ng()函数和我提供的alphaBetical字符串,培根将会在⽜奶之前,
但是⽕星会在⽜奶之后和⽜奶之前.
如果要根据您的区域设置进⾏排序.
如果要使⽤已为您的区域设置定义的整理顺序,可以设置区域设置并调⽤整理⽐较功能:/*
* To change the collating locale, use (for example):
setlocale(LC_COLLATE, "en.US");
*/
int iso_collating (const char *a, const char *b) {
return strcoll(a, b);
}
现在,通过更改区域设置,排序顺序将基于标准化的整理顺序.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。