1

给定一个 C 字符串:我如何编写一个函数来获取字符串中的下一个标记,以及一个可以在不使用全局变量的情况下查看下一个标记并返回它的函数?

我想要做的是有一个静态变量来保存字符串,当被调用时,它只会增加一个指针,它会重置那个静态变量,抛出已检索到的令牌。问题是:当我只是检索它时,我如何能够区分第一个调用(当它实际存储字符串时)和其他调用?

对此有什么想法吗?

编辑: 这就是我现在“有效”的东西,但我想确保它应该真正有效,而不仅仅是指针为空的巧合:

char next_token(char *line) {
    static char *p;
    if (p == NULL)
        p = line;
    else {
        char next_token = p[0];
        p++;
        return next_token;
    }
}
4

4 回答 4

0
typedef struct {
   char* raw;
   // whatever you need to keep track
} parser_t


void parser_init(parser_t* p, char* s)
{
   // init your parser
}

bool parser_get_token(parser_t* p, char* token)
{
   // return the token in "token"  or return a bool error ( or an enum of various errors)
}

bool parser_peek_token(parser_t* p, char* token)
{
  // same deal, but don't update where you are...
}
于 2012-10-24T23:11:17.193 回答
0

你有几个选择。一种方法是使用大致类似的接口strtok,其中传递非空指针初始化静态变量,传递空指针检索令牌。然而,在存在多线程的情况下,这相当丑陋、笨拙、容易出错并且有问题。

另一种可能性是使用具有单独函数(都在该文件中)的文件级静态变量来初始化静态变量,并从字符串中检索下一个标记。这稍微干净一些,但仍然存在大多数相同的问题。

第三种方法是让它(例如)像文件一样运行——用户调用 parse_open(例如),传入要解析的字符串。你返回一个不透明的句柄给他们。然后,他们每次想要另一个令牌时将其传递回(比如说)get_token。

于 2012-10-24T23:11:29.353 回答
0

您编辑的代码是错误的。您正在错误地处理 NULL 情况。

我最初的回答是模仿strtok这似乎是你想要的,但你已经澄清你想要单个字符。

if 条件应该是:

if (line != NULL) p = line;

而且您可能会删除,else以便代码每次都执行...除非您不希望在第一次调用时得到结果(尽管您至少应该返回一个值)。

你这样打电话:

char token = next_token(line);

while( 0 != (token = next_token(NULL)) ) {
    // etc
}
于 2012-10-24T23:22:39.707 回答
0

基本上,函数可以通过三种方式将信息传递回其调用者:

  • 通过全局变量
  • 通过返回值
  • 通过指针参数

而且,类似地,函数有一些方法可以在调用之间保持状态:

  • 通过全局或(函数)静态变量
  • 通过将其作为函数参数提供并在每次调用后返回
  • 通过指针参数。

词法分析器/标记器的一个很好的编码约定是使用返回值来传达消耗的字符数。(并且可能使用额外的指针变量来来回调用解析器状态)

这是 wakkerbot 的解析器:

STATIC size_t tokenize(char *string, int *sp);

用法:

STATIC void make_words(char * src, struct sentence * target)
{
    size_t len, pos, chunk;
    STRING word ;
    int state = 0; /* FIXME: this could be made static to allow for multi-line strings */

    target->size = 0;

    len = strlen(src);
    if (!len) return;

    for(pos=0; pos < len ; ) {

    chunk = tokenize(src+pos, &state);
        if (!chunk) { /* maybe we should reset state here ... */ pos++; }
        if (chunk > STRLEN_MAX) {
            warn( "Make_words", "Truncated too long string(%u) at %s\n", (unsigned) chunk, src+pos);
            chunk = STRLEN_MAX;
            }
        word.length = chunk;
        word.word = src+pos;

        if (word_is_usable(word)) add_word_to_sentence(target, word);

        if (pos+chunk >= len) break;
        pos += chunk;
    }
...
}
于 2012-10-25T00:01:28.523 回答