【问题标题】:Using strtok to tokenize html使用 strtok 标记 html
【发布时间】:2021-08-12 05:28:51
【问题描述】:

我希望提取恰好在<> 中找到的文本,同时还提取在>< 之间找到的内容。

例如:

  • <html> 只会返回 <html>

  • <title>This is a title</title> 将返回 <title>This is a title</title>

  • This is a title 将返回 This is a title

  • 最后<title>This is a weird use of < bracket</title> 应该返回<title>This is a weird use of < bracket</title>。我当前的版本识别为<title>This is a weird use of< bracket</title>

我将不胜感激任何 sn-ps 代码或前往解决方案的指导。

tldr,用<...>>...< 分别获取子字符串,而不会被浮动的...>......<... 难住。

编辑:不再使用strtok,如果您知道任何其他帮助或类似问题,将不胜感激。任何阅读的东西也将是非常有益的。注意:我们不是在尝试解析,只是对输入字符串进行 lex

只能使用 c 的标准库。

【问题讨论】:

  • strtok 不是你的朋友。您应该使用循环和测试显式解析 HTML 语法。
  • @chqrlie,感谢您的建议。
  • 哦,是的,strtok 在这里完全是错误的方法,因为 HTML 太复杂而无法以这种方式解析(而且正则表达式也不正确)。最好四处寻找可以为您执行此操作的 C 库;您可能需要一个 SAX 解析器,它一次为您提供一个令牌,而不是一个在内存中构建整个 HTML 树的 DOM 解析器(除非您正在寻找它)。
  • 只是尝试为有效 HTML 的子集构建基本验证器。我仅限于标准 C 库。

标签: c text-parsing


【解决方案1】:

到目前为止,我自己的解决方案,

按照@chqrlie 的建议...

void tokenize(char* stringPtr)
{
    char *flag;
    strcpy(flag, " ");
    /*We build this up as we iterate the string.
    Strtok was not suitable, build up tokens char by char */
    char tempToken[tokenLength];
    strcpy(tempToken, ""); // Init current token

    // Traverse string catching stuff between <...> and >...< seperately.
    for(int i =0; i<strlen(stringPtr);i++)
    {
        if (stringPtr[i]=='<' )
        {
            if (strcmp(flag, " ")==0)
            {
                putToken(tempToken);
                strcpy(tempToken,"");  // Tag starting, everything before it is a token. 
                strcpy(flag,"<");
                strcat(tempToken, flag);
            }
            else // Catches <...< 
            {
                presentError(stringPtr);
            }
        }
        else if (stringPtr[i]=='>')
        {
            if (strcmp(flag,"<")==0)
            {
                strcat(tempToken, ">");
                strcpy(flag," ");
                putToken(tempToken);
                strcpy(tempToken,"");
            }
            else // Cant have a > unless we saw < already
            {
                presentError(stringPtr);
            }
        }
        else // Manage non angle brackets
        {
            strncat(tempToken, &stringPtr[i],1 );
        }
    }
    putToken(tempToken); // Catches a line ending in a value, not a tag

    /* Notes 
    Floating <'s and >'s will be errored up
        - Special case ....<...>..., which is incorrect 
          will cause floating tokens, can be identified
    Unclosed tags i.e. </p will be tokenized verbatim, 
    thus can identify this mistake
    Unopened tags i.e. p> will be errored
    */
}

假设presentError() 终止词法分析。

可以进行一些改进,我愿意接受建议,但是这是第一个工作草案

【讨论】:

  • 您未能为stack 分配任何内存。 stack 永远不会被分配,也不应该被释放,它应该被分配到堆栈上。 strcpystrcat 很危险,因为它们没有检查以确保您不会超出分配的内存。
  • @Schwern,感谢您的反馈。假设传递到标记器的所有字符串的长度
  • stack 没有足够的内存," " 是两个字节,一个用于空格,一个用于终止 null。 malloc 仅在内存需要超出功能时才需要,使用自动内存分配它:char stack[] = ""。如果您只存储一个字符,请只使用一个字符:char stack = '\0'。最后,stack 不是stack。如果您在标签内,您可以像使用布尔值一样使用它来跟踪。 bool in_tag = false。您正在为基础知识而苦苦挣扎,我再次鼓励您考虑 JSON;它更简单。
  • @Schwern 指出 :) 承认称它为堆栈并不是最好的做法。
【解决方案2】:

只是尝试为有效 HTML 的子集构建基本验证器。

你不能,即使是基本的也不能。你会有太多的误报和否定。这是一个简单的例子。

<tag attribute=">" />

HTML 有许多不允许简单解析的特性。这是……

  • 平衡,如&lt;tag&gt;&lt;/tag&gt;"quotes"
  • 嵌套,如&lt;tag&gt;&lt;tag&gt;&lt;/tag&gt;&lt;/tag&gt;
  • 转义,如"escaped\"quote"
  • 其中嵌入了其他语言,例如 Javascript 和 CSS。

如果这是一个标记化练习,您可以定义一个非常具体的子集,但我建议使用更简单的方法,例如 JSON,它有一个 well defined grammar。这些通常使用 lexerparser 解析,但 JSON 足够小,可以手动编写。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
相关资源
最近更新 更多