C语言中的语法分析问题

C语言中的语法分析问题,c,parsing,pattern-matching,C,Parsing,Pattern Matching,我有一个字符串,格式如下: char *sampleLine = "name1: 251 name2: 23 name3: -67 name4: 0.00 name5: 310 name6: 410 name7: 54001 name8: 332 name9: SOME_TEXT name10: 3 name1: 181 235 237 name11: 11 name12: 240 241 242 243 244 245 246 247 248 249 250 name13: 0 name14:

我有一个字符串,格式如下:

char *sampleLine = "name1: 251 name2: 23 name3: -67 name4: 0.00 name5: 310 name6: 410 name7: 54001 name8: 332 name9: SOME_TEXT name10: 3 name1: 181 235 237 name11: 11 name12: 240 241 242 243 244 245 246 247 248 249 250 name13: 0 name14: 2 name15: 1 name16: 0 name17: 6 name18: 0 name19: 500 name20: 200 name21: 64 name22: 1 name23: 6 name24: 0 name25: 0";
字符串的一个问题是有些名称是重复的,但基本模式似乎是name:value。因此,我编写了一个算法,它将接受一个名称并返回一个值,但它似乎不起作用,并且没有考虑到名称重复的问题

例如:如果我通过name1,我会得到251,以此类推

以下是带有示例main的代码:

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

char* extractValue(char* name, char* buffer)
{
    char* begining = strstr(buffer,name);
    begining += strlen(name) + 2;

    if (begining != NULL)
    {
        char* end = strstr(begining,":");

        if (end != NULL)
        {
            end += 1;

            for (int i=0; i < strlen(end); i++)
            {
                if (end[i] != ':')
                {
                    i++;
                } else {
                    char namevalue[200];
                    bzero(namevalue,200);

                    strncpy(namevalue,begining,i);

                    for (int x=strlen(namevalue); x>0; x--)
                    {
                        if (namevalue[x] == ' ')
                        {
                            char* value = (char*)malloc(200);
                            bzero(value,200);

                            strncpy(value,namevalue,strlen(namevalue) - (strlen(namevalue) - x));

                            return value;
                        }
                    }
                    break;
                }
            }
        }
    }
    return NULL;
}


int main (int argc, char** argv)
{
    char *sampleLine = "name1: 251 name2: 23 name3: -67 name4: 0.00 name5: 310 name6: 410 name7: 54001 name8: 332 name9: SOME_TEXT name10: 3 name1: 181 235 237 name11: 11 name12: 240 241 242 243 244 245 246 247 248 249 250 name13: 0 name14: 2 name15: 1 name16: 0 name17: 6 name18: 0 name19: 500 name20: 200 name21: 64 name22: 1 name23: 6 name24: 0 name25: 0";

    char* value1  = extractValue("name1", sampleLine);
    char* value3  = extractValue("name3", sampleLine);
    char* value17 = extractValue("name17", sampleLine);

    printf("value 1 = %s\n",value1);
    printf("value 3 = %s\n",value3);
    printf("value 17 = %s\n",value17);

    return 0;
}
而非预期

value 1 = 251
value 3 = -67
value 17 = 6
两个微妙的错误

首先,

if (end[i] != ':')
{
   i++;
} else ..
通过在此处手动递增
i
,您将跳过一个字符,因为for循环已经递增了
i
。它似乎没有副作用,但只是因为

第二:问题的实际原因是您测量的字符串长度错误。通过从该位置向前扫描下一个
,可以找到名称值的开头(
begining
),然后找到其
end
。然后,向后追踪以查找上一个空格,该空格应为值的结尾。但是

for (i=0; i < strlen(end); i++)
并将
检查更改为

if (begining[i] == ':')
{
   char namevalue[200];
   ... (etc.)
(丢弃
i++
行)


零票 查找单个字符的稍微快一点的方法是
strchr

char* end = strchr(begining,':');
您可能希望找到更好的策略来定位
名称
。如果您正在查找
name1
,它可以找到
name12
以及
noname1

一种方法是使用
strtok
将字符串拆分为令牌。然后,任何以
结尾的内容都是一个可能的名称,下一个标记就是您要查找的值。省略,因为它本身就是一个很好的练习。(如果你想试试这个:)

最后,您可以不使用所有这些循环:-)


C还是C++,哪一个?这看起来像C。在C++中似乎更容易实现,但是问题似乎是C,所以我不会回答。这对于NAME2:23的工作非常有效,但是对于NAME12:240,241,242,243,244,245,246,247,248,249,250,这不起作用。如何提取这两种类型的值?在这种情况下,您可以使用自己的想法:从
开始
,向前扫描下一个
;如果找到,再次向后扫描以查找空间。在我更新
end
的地方更改此选项,
start
仍然很好。顺便说一句,如果您有
nameX:
但没有数据,那么它将返回一个空字符串。我的代码返回下一个名称。
if (begining[i] == ':')
{
   char namevalue[200];
   ... (etc.)
char* end = strchr(begining,':');
char* extractValue(char* name, char* buffer)
{
    char *start, *end, *ret_val;
    int length;
    char* begining = strstr(buffer,name);
    if (!begining)
        return NULL;
    start = begining + strlen(name);
    if (start[0] != ':')
        return NULL;
    start++;

//  skip initial spaces, if any
    while (*start == ' ')
        start++;
//  ptr points to the start of data. Find end.
    end = start;
    while (*end && *end != ' ')
        end++;

//  we have the correct string in start..end
    length = end-start;

//  it's a zero-terminated string so add 1 for the zero
    ret_val = (char *)malloc(length+1);
    strncpy (ret_val, start, length);
//  put the zero where it belongs
    ret_val[length] = 0;

    return ret_val;
}