我必须弄清楚我的主题字符串是否有任何不良字符(我绝对讨厌某些字符)。所以,如果我有一个名为str (char *str)
的字符串,并且如果找到字符串bad (char *bad)
中的任何字符,则拒绝字符串str
。现在我可以使用strcspn(str,bad)
来检查这个。但有人可以建议strcspn
的实施可能是什么?
一个天真的实现是针对str
的每个字符检查bad
的每个字符,如果找到匹配则拒绝str
。
for(i=0;str[i]!='\0';i++)
for(j=0;bad[j]!='\0';j++)
if(bad[j]==str[i])
return -1; //reject string
return 1; //accept string
或类似
for(i=0;str[i]!='\0';i++)
if(strchr(bad,str[i])) //will return non-NULL if str[i] is found in bad
return -1; //reject string
return 1; //accept string
答案 0 :(得分:8)
如果str
非常长(或者您要针对同一组坏字符检查多个字符串),则可以通过创建大小为256的查找表来获得一些性能,其中元素 i <如果ASCII代码 i 的字符为坏,则/ em>为1,否则为零:
int contains_bad(const char* str, const char* bad) {
unsigned short int table[256];
char* ch;
/* Prepare the lookup table */
memset(table, 0, 256);
for (ch = bad; *ch != 0; ch++)
table[*ch] = 1;
/* Test the string */
for (ch = str; *ch != 0; ch++)
if (table[*ch])
return -1;
return 1;
}
上面的代码是O(m + n)最坏的情况,其中 m 是 bad 的长度而 n 的长度是 STR ;你的解决方案是O(mn)最坏的情况。
更新:这是该函数的替代版本,它将查找表保存在静态存储中,并且每255次调用只清除一次。
int contains_bad(const char* str, const char* bad) {
static unsigned short int table[256];
static unsigned short int marker = 255;
char* ch;
/* Prepare the lookup table */
if (marker == 255) {
memset(table, 0, 256);
marker = 1;
} else {
marker++;
}
for (ch = bad; *ch != 0; ch++)
table[*ch] = marker;
/* Test the string */
for (ch = str; *ch != 0; ch++)
if (table[*ch] == marker)
return -1;
return 1;
}
答案 1 :(得分:1)
如果您关心最坏情况的性能和/或线程安全性,这里有一个将表保持在堆栈中的变体。
#include <limits.h>
#include <stddef.h>
int contains_bad(const char *str, const char *bad) {
size_t hint[UCHAR_MAX];
size_t len_bad;
for (len_bad = 0; bad[len_bad]; len_bad++) {
hint[(unsigned char)bad[len_bad] - 1] = len_bad;
}
for (; *str; str++) {
size_t i = hint[(unsigned char)*str - 1];
if (i < len_bad && *str == bad[i]) return 1;
}
return 0;
}
(对于语言律师:从技术上讲,未初始化的数组hint
可能有潜伏的陷阱表示。如果你知道这意味着什么,并且实际上关心C程序在长期死平台上的行为,一个解决方案,如果{ {1}}是一个集合,因此不超过bad
个字符,是要将UCHAR_MAX
更改为size_t hint[UCHAR_MAX]
,因为保证unsigned char不会有陷阱表示。)