当文件包含按以下方式格式化的行时,如何从文件中读取行:
<string> "<string>"
第一个字符串不能包含空格。引号中的字符串可以包含空格。
在阅读文件到char
array
之后,我尝试了一些
sscanf(buffer, "%s", string1);
sscanf(buffer, "%*s \"%[^\"]\"", string2);
问题是我为某些行获得了一些奇怪的字符。大多数字符都很好,但对于长字符串,我会得到一些不应出现的字符。
编辑:
看起来这个问题可能与sscanf
无关。当我在string1
之后立即打印string2
和sscanf
时,我得到了正确的输出。我的程序设置方式我必须malloc
新内存并将结果复制到char*
。当我打印出后一种结果时会出现奇怪的行为。我使用char *cpystring1 = malloc(strlen(string1))
然后使用memcpy(cpystring1, string1, strlen(string1)
。这一直对我有用,但是,也许这不是最好的方法?
问题已解决:
请查看我留下的最后一条评论。
答案 0 :(得分:1)
正如BLUEPIXY中comment所述,一个问题是“你有足够的空间来存储字符串吗?”确实,你的变量是char string1[SOME_SIZE];
还是char *string1;
,如果是后者,你如何为它们分配空间?奇怪的额外字符等症状通常是由于读取数据的空间不足造成的。
您可以将两个操作合并为一个操作。你还应该限制你读的大小;你应该检查你的阅读是否成功。假设你有两个大小为128的数组,你可以编写
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"", string1, string2) != 2)
…format error…
请注意,格式字符串中指定的数字是字符串的最大长度,不包括空字节。这与图书馆的其他部分并不完全一致,但是在有C标准之前很久就已经建立了实践,改变规则会比修复规则更多。
请注意,使用上面的代码,您永远不会知道是否存在尾随双引号。如果您也需要这些信息,那么您必须更加努力地工作:
int offset = 0;
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"%n", string1, string2, &offset) != 2 || offset == 0)
…format error…
最后,如果您使用POSIX系统,m
和%s
以及%c
操作的%[…]
修饰符会动态分配正确的空间量读取的数据(但您将指针传递给char *
以使转换规范使用而不是普通的char *
):
int offset = 0;
char *tag = 0;
char *value = 0;
if (sscanf(buffer, "%ms \"%m[^\"]\"%n", &tag, &value, &offset) != 2 || offset == 0)
…format error…
请注意,某些系统(例如Mac OS X 10.10.1 Yosemite)不支持m
修饰符,即使它是sscanf()
的POSIX 2008规范的一部分。 GNU C库(例如在Linux上找到)确实支持它。
值得考虑sscanf()
是否是处理此数据的最佳方式。可以使用它:我刚刚展示了(当你写这个问题时你得到了大部分内容)。然而,准确使用它是一个棘手的功能 - 这是礼貌的。关于sscanf()
的好处是,你可以实现“如果一开始你不成功,尝试,尝试,再试一次”。使用像scanf()
这样的直接I / O函数,一般情况下你不能再试一次。但是,您也可以使用字符串操作来获得所需的输出,但这样做的简单方法会破坏输入字符串:
char *tag = buffer + strspn(buffer, " \t"); // Skip leading blanks and tabs
char *eot = tag + strcspn(tag, " \t"); // Tag does not contain blanks or tabs
if (*eot == '\0')
…report format error (no value after tag); do not continue…
*eot++ = '\0'; // Null terminate the tag
char *value = eot + strspn(eot, " \t"); // Skip separating blanks and tabs
if (*value++ != '"')
…report format error (missing open double quote); do not continue…
char *eov = strchr(value, '"');
if (eov == 0)
…report format error (missing close double quote); do not continue…
*eov = '\0';
还有其他方法可以进行扫描,但strspn()
和strcspn()
是C89及其后续版本标准中标准的被忽略的函数。
使用GCC 4.8.2在Ubuntu 14.04 LTS上测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void parsing(char *buffer)
{
char *tag = buffer + strspn(buffer, " \t"); // Skip leading blanks and tabs
char *eot = tag + strcspn(tag, " \t"); // Tag does not contain blanks or tabs
if (*eot == '\0')
{
printf("Got tag <<%s>> but no following data\n", tag);
return;
}
*eot++ = '\0'; // Null terminate the tag
char *value = eot + strspn(eot, " \t"); // Skip separating blanks and tabs
if (*value++ != '"')
{
printf("Got tag <<%s>> but it is not followed by a double-quoted string\n", tag);
return;
}
char *eov = strchr(value, '"');
if (eov == 0)
{
printf("Got tag <<%s>> and value <<%s>> but it is not followed by a double-quote\n", tag, value);
return;
}
*eov = '\0';
printf("<<%s>> <<%s>>\n", tag, value);
}
int main(void)
{
char buffer[] = " \ttagname \" corresponding tag \tvalue is OK \" ";
{
int offset = 0;
char string1[128];
char string2[128];
if (sscanf(buffer, "%127s \"%127[^\"]\"%n", string1, string2, &offset) != 2 || offset == 0)
printf("sscanf() 1 failed\n");
else
printf("<<%s>> <<%s>>\n", string1, string2);
}
{
int offset = 0;
char *tag = 0;
char *value = 0;
if (sscanf(buffer, "%ms \"%m[^\"]\"%n", &tag, &value, &offset) != 2 || offset == 0)
printf("sscanf() 2 failed\n");
else
printf("<<%s>> <<%s>>\n", tag, value);
free(tag);
free(value);
}
parsing(buffer);
return 0;
}
输出:
<<tagname>> << corresponding tag value is OK >>
<<tagname>> << corresponding tag value is OK >>
<<tagname>> << corresponding tag value is OK >>
答案 1 :(得分:0)
使用strchr
:
char *space1 = strchr(buffer, ' ');
*space1 = '\0'; /* terminate the first string in place */
space1++; /* move pointer to beginning of string2 */
printf("String1 = \"%s\"\n", buffer);
printf("String2 = \"%s\"\n", space1);
注意:上面的代码不包含安全检查,只是为了说明这个想法。我也没有包含摆脱第二个字符串周围的"
字符的逻辑,但这应该很容易。提示:将space1
增加2,并将"
替换为\0
。