【问题标题】:String parsing in C. Copying a part of a string to another stringC中的字符串解析。将字符串的一部分复制到另一个字符串
【发布时间】:2014-05-26 19:31:27
【问题描述】:

我正在尝试编写一个函数,它将字符串中的所有转义序列转换为不可打印的形式。基本上,如果我有一个字符串“这个 \n 换行”,我希望它是“这个 换行”。到目前为止,我已经知道了。我从 main 调用:

int main()
{
    unescape("This \\n\\n is \\t\\t\\t string number \\t 7.");
    return 0;
}

char* unescape(char* s)
{
    char *esc[2] = {"\\n", "\\t"};
    int i;
    char* uus = (char*)calloc(80, sizeof(char));
    char* uus2 = (char*)calloc(80,sizeof(char));

    strncpy(uus, s, strlen(s));

    for(i = 0; i < 2; i++)
    {
        while(strstr(uus, esc[i]) != NULL) //checks if \\n can be found
        {
            //printf("\n\n%p\n\n", strstr(uus, esc[i]));
            int c = strstr(uus, esc[i]) - uus; //gets the difference between the address of the beginning of the string and the location
                                           //where the searchable string was found
            uus2 = strncpy(uus2, uus, c); //copies the beginning of the string to a new string

            //add check which esc is being used
            strcat(uus2, "\n"); //adds the non-printable form of the escape sequence
            printf("%s", uus2);

            //should clear the string uus before writing uus2 to it 
            strncpy(uus, uus2, strlen(uus2)); //copies the string uus2 to uus so it can be checked again
        }
    }
    //this should return something in the end. 
}

基本上,我现在需要做的是从字符串 uus 中取出 "\n" 之后的部分并将其添加到字符串 uus2 中,这样我就可以再次运行 while 循环。我考虑过使用 strtok 但碰壁了,因为它使用某种分隔符创建两个单独的字符串,在我的情况下并不总是存在。

edit:将字符串的其余部分添加到 uus2 应该在 strncpy 之前。这是没有它的代码。

edit vol2:这是我最终使用的有效代码。基本上编辑了 Ruud 的版本,因为我必须使用的函数必须返回一个字符串。非常感谢。

char* unescape(char* s)
{
    char *uus = (char*) calloc(80, sizeof(char));
    int i = 0;

    while (*s != '\0')
    {
        char c = *s++;
            if (c == '\\' && *s != '\0')
            {
                c = *s++;
                switch (c)
                {
                case 'n': c = '\n'; break;
                case 't': c = '\t'; break;
                }
            }
        uus[i] = c;
        i++;
    }
    uus[i] = '\0';
    return uus;
}

【问题讨论】:

  • 您的原始代码至少存在 3 个问题:(1)您忙于来回复制数据,以至于忘记关闭这些转义字符留下的“漏洞”; (2) 你留下了未终止的字符串,因为strncpy 从未复制尾随\0; (3) 由于strcat(uus2, "\n"); 中的\n 硬编码,\t 被换行符替换。

标签: c string text-parsing arrays


【解决方案1】:

我同意 Anonymouse 的观点。首先替换所有\n,然后替换所有\t 既笨拙又低效。相反,只需遍历字符串一次,同时替换所有转义字符。

我在下面的代码示例中留下了空间分配;恕我直言,这是一项单独的职责,不是算法的一部分,因此不属于同一功能。

void unescape(char *target, const char *source)
{
    while (*source != '\0')
    {
        char c = *source++;
        if (c == '\\' && *source != '\0')
        {
            c = *source++;
            switch (c)
            {
                case 'n': c = '\n'; break;
                case 't': c = '\t'; break;
            }
        }
        *target++ = c;
    }
    *target = '\0';
}

编辑: 这是一个替代版本,使用 Anonymouse 建议的strchr。 这种实现应该更快,尤其是在转义字符相对较少的非常长的字符串上。 我发布它主要是为了演示优化如何使您的代码更复杂且可读性更低;因此,可维护性较差且更容易出错。详细讨论见:http://c2.com/cgi/wiki?OptimizeLater

void unescape(char *target, const char *source)
{
    while (*source != '\0')
    {
        if (*source++ == '\\' && *source != '\0')
        {
            char c = *source++;
            switch (c)
            {
                case 'n': c = '\n'; break;
                case 't': c = '\t'; break;
            }
            *target++ = c;
        }
        else
        {
            const char *escape = strchr(source--, '\\');
            int numberOfChars = escape != NULL ? escape - source : strlen(source);
            strncpy(target, source, numberOfChars);
            target += numberOfChars;
            source += numberOfChars;
        }
    }
    *target = '\0';
}

【讨论】:

  • 打算试试这个。不过,只是好奇,有没有办法让我的方法成功?只是想知道以供将来参考,因为我花了很多时间试图以这种方式实现它。
  • 我的带有 strchr 的版本会更快。另外我正在(错误地)搜索 \\n - 所以删除 IF 语句。最后 Ruud 的函数原型比提问者更好, const 是你的朋友,特别是如果你尝试修改一个常量字符串(例如“This \\n\\n is \\t\\t\\t string number \\t 7 .")
  • 我最终使用了 Ruud 的代码版本。我用最终代码编辑了我的第一篇文章。遗憾的是,我在理解 Anonymouse 的代码时遇到了一些困难,但非常感谢你们俩。
  • @Anonymous:确实,strchr 更快,但速度并不是一切。请看我的编辑;以及我超链接的 wiki 讨论。
【解决方案2】:

你最好用这个...

char *p;

p = input_string;
while ((p=strchr (p, '\\')) != NULL)
{
  if (p [1] == '\\')
  {
     switch (p [2])
     {
     case 'n' :
       // handle \n
       break;
     case 't' :
       // handle tab
       break;    
     }
  }
  else
    p++;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-05
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 2017-06-06
    • 2022-11-30
    • 1970-01-01
    • 2011-01-08
    相关资源
    最近更新 更多