【问题标题】:C Tokenizer - How does it work?C Tokenizer - 它是如何工作的?
【发布时间】:2010-07-30 14:36:52
【问题描述】:

这是如何工作的?

我知道使用它你传入:

  • 开始:字符串(例如“第 1 项、第 2 项、第 3 项”)
  • delim:分隔符字符串(例如“,”)
  • tok: 对包含令牌的字符串的引用
  • nextpos(可选):引用原始字符串中下一个标记开始的位置
  • sdelim(可选):指向将包含标记起始分隔符的字符的指针
  • edelim(可选):指向一个字符的指针,该字符将包含标记的结束分隔符

代码:

#include <stdlib.h>
#include <string.h>

int token(char* start, char* delim, char** tok, char** nextpos, char* sdelim, char* edelim) {
    // Find beginning:
    int len = 0;
    char *scanner;
    int dictionary[8];
    int ptr;

    for(ptr = 0; ptr < 8; ptr++) {
        dictionary[ptr] = 0;
    }

    for(; *delim; delim++) {
        dictionary[*delim / 32] |= 1 << *delim % 32;
    }

    if(sdelim) {
        *sdelim = 0;
    }

    for(; *start; start++) {
        if(!(dictionary[*start / 32] & 1 << *start % 32)) {
            break;
        }
        if(sdelim) {
            *sdelim = *start;
        }
    }

    if(*start == 0) {
        if(nextpos != NULL) {
            *nextpos = start;
        }
        *tok = NULL;
        return 0;
    }

    for(scanner = start; *scanner; scanner++) {
        if(dictionary[*scanner / 32] & 1 << *scanner % 32) {
            break;
        }
        len++;
    }

    if(edelim) {
        *edelim = *scanner;
    }

    if(nextpos != NULL) {
        *nextpos = scanner;
    }

    *tok = (char*)malloc(sizeof(char) * (len + 1));

    if(*tok == NULL) {
        return 0;
    }

    memcpy(*tok, start, len);
    *(*tok + len) = 0;


    return len + 1;
}

我得到了大部分,除了:

dictionary[*delim / 32] |= 1 &lt;&lt; *delim % 32;

dictionary[*start / 32] &amp; 1 &lt;&lt; *start % 32

是魔法吗?

【问题讨论】:

  • 我知道这两行代码可以找到分隔符,但它没有循环遍历分隔符字符串?

标签: c algorithm tokenize


【解决方案1】:

由于分隔符的每个字符都是 8 位(sizeof(char) == 1 字节),因此限制为 256 个可能的值。

字典分为 8 块 (int dictionary[8]),每块 32 种可能性(sizeof(int) >= 4 字节)和 32 * 8 = 256。

这形成了一个 256 位的值矩阵。然后它为分隔符 (dictionary[*delim / 32] |= 1 &lt;&lt; *delim % 32;) 中的每个字符打开标志。数组的索引是*delim / 32,或字符的 ASCII 值除以 32。由于 ASCII 值的范围是 0 到 255,这个除法产生的值是 0 到 7 的余数。余数是打开哪个位,由模运算决定。

如果相应的 ASCII 字符存在于分隔符中,所有这一切都会将 256 位矩阵的某些位标记为真。

然后确定一个字符是否在分隔符中只是在 256 位矩阵中查找 (dictionary[*start / 32] &amp; 1 &lt;&lt; *start % 32)

【讨论】:

    【解决方案2】:

    他们通过将 8 x 32 = 256 位表存储在字典中来存储出现的字符。

    dictionary[*delim / 32] |= 1 << *delim % 32;
    

    设置*delim对应的位

    dictionary[*start / 32] & 1 << *start % 32
    

    检查位

    【讨论】:

      【解决方案3】:

      好的,所以如果我们为delimiter 发送字符串",",那么dictionary[*delim / 32] |= 1 &lt;&lt; *delim % 32 将是dictionary[1] = 4096。表达式dictionary[*start / 32] &amp; 1 &lt;&lt; *start % 32 只是检查匹配的字符。

      让我感到困惑的是为什么他们不直接使用char 比较。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-29
        • 1970-01-01
        • 2013-05-05
        • 1970-01-01
        相关资源
        最近更新 更多