【问题标题】:How to Find all occurrences of a Substring in C如何在 C 中查找所有出现的子字符串
【发布时间】:2015-04-25 14:43:34
【问题描述】:

我正在尝试用 C 语言编写一个解析程序,该程序将从 HTML 文档中获取某些文本段。为此,我需要在文档中找到子字符串“name”的每个实例;但是,C 函数 strstr 只查找子字符串的第一个实例。我找不到找到第一个实例之外的任何内容的函数,并且我考虑在找到每个子字符串后删除它,以便 strstr 将返回下一个。我无法让这两种方法中的任何一种发挥作用。

顺便说一句,我知道 while 循环将其限制为六次迭代,但我只是在测试这个,看看我是否可以让函数首先工作。

while(entry_count < 6)
{   
    printf("test");
    if((ptr = strstr(buffer, "\"name\":")) != NULL)
    {   
        ptr += 8;
        int i = 0;
        while(*ptr != '\"')
        {   
            company_name[i] = *ptr;
            ptr++;
            i++;
        }   
        company_name[i] = '\n';
        int j;
        for(j = 0; company_name[j] != '\n'; j++)
            printf("%c", company_name[j]);
        printf("\n");
        strtok(buffer, "\"name\":");
        entry_count++;
    }   
}   

【问题讨论】:

  • strstr(strstr(html, "name") + 1, "name") 找到"name" 的第二次出现(前提是内部strstr 没有返回NULL)

标签: html c algorithm parsing


【解决方案1】:

只需将返回的指针加一,传回strstr()即可找到下一个匹配项:

char *ptr = strstr(buffer, target);
while (ptr) {
    /* ... do something with ptr ... */
    ptr = strstr(ptr+1, target);
}

附言。虽然您确实可以做到这一点,但我想建议您考虑使用更合适的工具来完成这项工作:

  • C 是一种非常低级的语言,尝试在其中编写字符串解析代码很费力(尤其是如果您坚持从头开始编写所有代码,而不是使用现有的解析库或解析器生成器)并且容易错误(其中一些,如缓冲区溢出,可能会造成安全漏洞)。有许多更高级的脚本语言(如 Perl、Ruby、Python 甚至 JavaScript)非常更适合此类任务。

  • 在解析 HTML 时,您确实应该使用适当的 HTML 解析器(最好结合使用好的 DOM 构建器和查询工具)。这将允许您根据文档的 结构 定位所需的数据,而不仅仅是匹配原始 HTML 源代码中的子字符串。真正的 HTML 解析器还将透明地处理字符集转换和字符实体解码等问题。 (是的, C 的 HTML 解析器,例如 GumboHubbub,所以即使你坚持使用 C,你也可以而且应该使用一个。)

    李>

【讨论】:

    【解决方案2】:
    /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *\
     *                                                  *
     *  SubStg with parameters in the execution line    *
     *  Must use 2 parameters                           *
     *  The 1st is the string to be searched            *
     *  The 2nd is the substring                        *
     *  e.g.:  ./Srch "this is the list" "is" >stuff    *
     *  e.g.:  ./Srch "$(<Srch.c)" "siz"                *
     *  (ref: http://1drv.ms/1PuVpzS)                   *
     *  © SJ Hersh 15-Jun-2020                          *
     *                                                  *
    \*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    typedef char* char_ptr;
    typedef unsigned int* int_ptr;
    #define NOMEM ( int_ptr )0
    
    int main( int parm, char** stgs )
    {
       char_ptr string, substg;
       unsigned int sizstg, sizsub, endsiz, *ary;
       int_ptr startmem;
       register unsigned int x, y, ctr=0;
    
       if( parm != 3 )
       {
          printf( "ERR: You need exactly 2 string arguments\n" );
          return ( -8 );
       }
    
       string = stgs[ 1 ];
       substg = stgs[ 2 ];
       sizstg = strlen( string );
       sizsub = strlen( substg );
       endsiz = sizstg - sizsub + 1;
    
    
          /* Check boundary conditions: */
    
    if( ( sizstg == 0 ) || ( sizsub == 0 ) )
    {
       printf( "ERR: Neither string can be nul\n" );
       return( -6 );
    }
    
    if( sizsub > sizstg )
    {
       printf( "ERR: Substring is larger than String\n" );
       return( -7 );
    }
    
    if( NOMEM == ( ary = startmem = malloc( endsiz * sizeof( int ) ) ) )
    {
       printf( "ERR: Not enough memory\n" );
       return( -9 );
    }
    
    
          /* Algorithm */
    
       printf( "Positions:\t" );
    
       for( x = 0; x < endsiz; x++ )
          *ary++ = string[ x ] == substg[ 0 ];
    
       for( y = 1, ary = startmem; y < sizsub; y++, ary = startmem )
          for( x = y; x < ( endsiz + y ); x++ )
             *ary++ &= string[ x ] == substg[ y ];
    
       for( x = 0; ( x < endsiz ); x++ )
          if( *ary++ )
          {
             printf( "%d\t", x );
             ctr++;
          }
    
       printf( "\nCount:\t%d\n", ctr );
       free( startmem );
       return( 0 );
    }
    

    【讨论】:

    • 我的算法有一些有趣的地方: • 没有保留字符(例如,您可以搜索包含空格的子字符串。) • 一切都在内存中完成,并且只分配一次.因此,程序不必不断地寻找空间。 • “循环”仅执行逻辑运算符。这对 CPU 速度的影响最小。 • 因此,我相信这个方案相当有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-20
    • 2013-03-22
    • 2015-12-23
    • 2022-12-15
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多