赞
踩
保持一致的话一起…
对于单词列表,将“相同”的单词组合在一起(即使情况不同)往往更为有用.例如:
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;
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_collating()函数和我提供的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);
}
现在,通过更改区域设置,排序顺序将基于标准化的整理顺序.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。