如何将strtok与每个非alpha字符一起用作分隔符? (C)

时间:2014-10-07 18:51:06

标签: c file

所以我有一个字符串:

**BOB**123(*&**blah**02938*(*&91820**FOO**

我希望能够使用strtok来消除每个单词。分隔符是每个不是字母的单个字符。

我被建议isalpha给我们,但不知道我会怎么做。有没有办法在不指定每个非字母字符的情况下执行此操作?

不幸的是,不允许使用正则表达式库。

4 个答案:

答案 0 :(得分:5)

#include <stdio.h>
#include <ctype.h>

char *strtok_t(char *str, int (*test)(int ch)){
    static char *store = NULL;
    char *token;
    if(str != NULL){
        store = str;
    }
    if(store == NULL) return NULL;
    while(*store && !test(*store)){//skip delimiter
        ++store;
    }
    if(*store == '\0') return NULL;
    token=store;
    while(*store && test(*store)){
        ++store;
    }

    if(*store == '\0'){
        store = NULL;
    } else {
        *store++ = '\0';
    }
    return token;
}

int main(void){
    char str[128] = "BOB123(&blah02938(*&91820FOO";
    char *token;
    for(token = strtok_t(str, isalpha); token ; token = strtok_t(NULL, isalpha)){
        printf("%s\n", token);
    }
    return 0;
}

答案 1 :(得分:4)

一种可以使这更容易的方法是首先使用空格覆盖所有非字母字符:

for (char *p = str; *p; p++)
    if (!isalpha(*p)) *p = ' ';

现在您可以使用strtok(str, " ")

答案 2 :(得分:1)

首先,您必须创建一个非alpha字符列表:

char *myString = "fhewuidnjkl123782107381290z890zh";
char nonAlphachars[0xFF];
memset(nonAlphachars, 0, 0xFF);
int i = 0;    
int c = 1;
for(; c <= 0xFF; c++)
{
   if(!isalpha(c))
   {
      nonAlphachars[i++] = c;
   }
}

这样,您就可以strtok使用myString

char *tok = strtok(myString, nonAlphachars);

现在你只需要迭代你的令牌就可以了。请注意:那只是一个未经测试的(!)选秀,但我猜你会得到这个想法。 如果你希望你的程序有效:在一个单独的字符串中硬编码所有非alpha-chars,完全丢弃循环并使用它...丑陋但非常快(不同于所有其他答案)

顺便说一句:这些都是数字表示中的所有非alpha字符,只是发现了差距......我会把那个留给你;-):

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 91 92 93 94 95 96 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 

答案 3 :(得分:1)

可能可能会使用strtok来实现这一点,但是推出自己的可能更容易。下面是一个使用自定义结构来保存标记符的状态和结果的示例。状态只是指向字符串的指针,必须使用字符串对其进行标记。

结果表示该字符串的子字符串为起始指针和长度的组合。结果不是零终止,所以你必须小心。这种方法的好处是解决方案不会分配额外的内存,也不会覆盖原始字符串,因此与strtok不同,它适用于只读字符串。

使用返回1或0的函数调用tokeniser本身,具体取决于是否找到了新的令牌,这样可以简化循环语法。

这里是:

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>      /* for isalpha(c) */

struct alpha_t {
    const char *p;      /* Pointer int string; must be initialised */
    const char *str;    /* start of current token */
    int len;            /* length of token */
};

/*
 *      Get next alpha token from string; alpha->p must be initialised
 *      to the (possible read-only) string to work on.
 */
int next_alpha(struct alpha_t *alpha)
{
    if (alpha->p == NULL) return 0;

    /* Skip non-alpha and check for end of string */
    while (*alpha->p && !isalpha(*alpha->p)) alpha->p++;
    if (*alpha->p == 0) return 0;

    /* Read token of alpha charactzers */
    alpha->str = alpha->p;
    while (isalpha(*alpha->p)) alpha->p++;
    alpha->len = alpha->p - alpha->str;

    return 1;
}

/*
 *      Example client code
 */
int main()
{
    char *str = "BOB123(&blah02938(*&91820FOO";
    struct alpha_t token = {str};

    while (next_alpha(&token)) {
        printf("'%.*s'\n", token.len, token.str);
    }

    return 0;   
}

此解决方案使用isalpha,如您所建议的那样。它很容易扩展到其他函数 - 您甚至可以在非分隔符函数上传递分隔符作为参数,或者使其成为结构的一部分,用于可自定义的标记器。