使用 sscanf 从字符串中读取多个单词
Read more than one word from string with sscanf
我正在尝试从文件中读取格式化内容。为此,我使用 fgets()
和 sscanf()
逐行阅读。
文件的内容应该是table。一行将类似于以下示例:
456 2 39 chained_words 62.5 // comment with more than one word
要阅读它,我使用:
fgets(temp,MAXLINELENGTH,file);
sscanf(temp,"%d %d %d %s %f // %s",&num1,&num2,&num3,word,&num4,comment);
前五个元素加上 //
之后的第一个单词可以正常工作,但问题是我需要将整个注释存储在 comment
char * 变量中。我尝试了其他帖子中提出的多种解决方案,例如指定排除某些字符的格式,但没有任何效果。
对于解决问题的任何提示,我将不胜感激!
根据您的评论,如果您要在现有 comment
之后添加另一个数字,这会使事情变得有点复杂。原因是 comment
包含多个单词,您没有要搜索的离散端。
然而,C 很少让你失望。每当您需要从行或缓冲区解析数据时,您会查看数据的格式并询问 "What am I going to use as my reference for the beginning or end of what I need?" 这里,没有任何注释,我们将需要使用缓冲区的末尾作为参考并向后工作.
我们假设值是行中换行符之前的最后一个值(后面没有制表符或 spaces)。我们可以向后循环,直到找到要验证的最后一个非白色 space 字符,但出于此处的目的,我们做出假设。
为了解决这个问题,我们将解析行分成两部分。我们可以通过我们最初的 sscanf
调用以可靠的方式阅读评论之前的所有内容。因此,我们将考虑第 1 部分一行的第一部分(直到并包括浮点数)中的所有内容,以及第 2 部分注释字符 //
之后的所有内容。您 read/parse 像往常一样第 1 部分:
sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);
在一行中搜索特定字符,我们有一个手动的逐字符比较(我们一直都有),我们在 [=22= 中有 strchr
和 strrchr
函数] 将在一行文本中搜索给定字符的第一次 (strchr
) 或最后一次 (strrchr
) 出现。这两个函数 return 一个 指向字符串中该字符 的指针。
从我们行的末尾向后工作,如果我们找到 /
,我们现在有一个指针(字符串中的地址)指向注释开头之前的最后一个 '/'
。我们现在使用我们的指针将行的整个剩余部分读入 comment
(值和全部)。
p = strrchr (line, '/'); /* find last '/' in line */
sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value */
现在我们只在 comment
中工作(而不是 line
)。我们知道如果我们从 comment
的末尾向后寻找 space ' '
,我们将能够读取我们的最后一个值。在我们读取最后一个值之后,因为我们的指针指向值之前的地址,我们知道我们可以 null-terminate
comment
在指针处完成我们的解析。
p = strrchr (comment, ' '); /* find last space in file */
sscanf (p, " %d", &d4); /* read last value into d4 */
*p = 0; /* null-terminate comment */
(注意: 如果需要,您可以 check/removed comment
中的任何尾随 space,但为了我们的目的,它被省略了)
把它们放在一起你会得到这样的东西:
快速示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 128
int main (int argc, char **argv) {
if (argc < 2 ) { /* check for at least 1 argument */
fprintf (stderr, "error: insufficient input, usage: %s filename\n",
argv[0]);
return 1;
}
char line[MAXS] = {0};
char word[MAXS] = {0};
char comment[MAXS] = {0};
char *p = NULL;
size_t idx = 0;
int d1, d2, d3, d4;
float f1 = 0.0;
FILE *fp = NULL;
d1 = d2 = d3 = d4 = 0;
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file */
fprintf (stderr, "error: file open failed '%s'.", argv[1]);
return 1;
}
while (fgets (line, MAXS, fp) != NULL) /* read each line in file */
{
/* read buffer through first float */
sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);
p = strrchr (line, '/'); /* find last '/' in line */
sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value */
p = strrchr (comment, ' '); /* find last space in file */
sscanf (p, " %d", &d4); /* read last value into d4 */
*p = 0; /* null-terminate comment */
printf ("\nline : %zu\n\n %s\n", idx, line);
printf (" d1 : %d\n d2 : %d\n d3 : %d\n d4 : %d\n f1 : %.2f\n",
d1, d2, d3, d4, f1);
printf (" chained : %s\n comment : %s\n", word, comment);
idx++;
}
fclose (fp);
return 0;
}
输入
$ cat dat/strwcmt.txt
456 2 39 chained_words 62.5 // comment with more than one word 227
457 2 42 more_chained_w 64.5 // another comment 228
458 3 45 s_n_a_f_u 66.5 // this is still another comment 229
输出
$ ./bin/str_rd_mixed dat/strwcmt.txt
$ ./bin/str_rd_mixed dat/strwcmt.txt
line : 0
456 2 39 chained_words 62.5 // comment with more than one word 227
d1 : 456
d2 : 2
d3 : 39
d4 : 227
f1 : 62.50
chained : chained_words
comment : comment with more than one word
line : 1
457 2 42 more_chained_w 64.5 // another comment 228
d1 : 457
d2 : 2
d3 : 42
d4 : 228
f1 : 64.50
chained : more_chained_w
comment : another comment
line : 2
458 3 45 s_n_a_f_u 66.5 // this is still another comment 229
d1 : 458
d2 : 3
d3 : 45
d4 : 229
f1 : 66.50
chained : s_n_a_f_u
comment : this is still another comment
注意: 处理此问题的不同方法没有限制。这只是一种方法。另一种方法是将整行 标记化 成单独的单词,检查每个单词是否以数字开头(并包含 '.' 表示浮点数),然后简单地转换所有数字并连接所有根据需要使用非数字词。由你决定。你的工具箱越大,你就会看到越多的方法。
我正在尝试从文件中读取格式化内容。为此,我使用 fgets()
和 sscanf()
逐行阅读。
文件的内容应该是table。一行将类似于以下示例:
456 2 39 chained_words 62.5 // comment with more than one word
要阅读它,我使用:
fgets(temp,MAXLINELENGTH,file);
sscanf(temp,"%d %d %d %s %f // %s",&num1,&num2,&num3,word,&num4,comment);
前五个元素加上 //
之后的第一个单词可以正常工作,但问题是我需要将整个注释存储在 comment
char * 变量中。我尝试了其他帖子中提出的多种解决方案,例如指定排除某些字符的格式,但没有任何效果。
对于解决问题的任何提示,我将不胜感激!
根据您的评论,如果您要在现有 comment
之后添加另一个数字,这会使事情变得有点复杂。原因是 comment
包含多个单词,您没有要搜索的离散端。
然而,C 很少让你失望。每当您需要从行或缓冲区解析数据时,您会查看数据的格式并询问 "What am I going to use as my reference for the beginning or end of what I need?" 这里,没有任何注释,我们将需要使用缓冲区的末尾作为参考并向后工作.
我们假设值是行中换行符之前的最后一个值(后面没有制表符或 spaces)。我们可以向后循环,直到找到要验证的最后一个非白色 space 字符,但出于此处的目的,我们做出假设。
为了解决这个问题,我们将解析行分成两部分。我们可以通过我们最初的 sscanf
调用以可靠的方式阅读评论之前的所有内容。因此,我们将考虑第 1 部分一行的第一部分(直到并包括浮点数)中的所有内容,以及第 2 部分注释字符 //
之后的所有内容。您 read/parse 像往常一样第 1 部分:
sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);
在一行中搜索特定字符,我们有一个手动的逐字符比较(我们一直都有),我们在 [=22= 中有 strchr
和 strrchr
函数] 将在一行文本中搜索给定字符的第一次 (strchr
) 或最后一次 (strrchr
) 出现。这两个函数 return 一个 指向字符串中该字符 的指针。
从我们行的末尾向后工作,如果我们找到 /
,我们现在有一个指针(字符串中的地址)指向注释开头之前的最后一个 '/'
。我们现在使用我们的指针将行的整个剩余部分读入 comment
(值和全部)。
p = strrchr (line, '/'); /* find last '/' in line */
sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value */
现在我们只在 comment
中工作(而不是 line
)。我们知道如果我们从 comment
的末尾向后寻找 space ' '
,我们将能够读取我们的最后一个值。在我们读取最后一个值之后,因为我们的指针指向值之前的地址,我们知道我们可以 null-terminate
comment
在指针处完成我们的解析。
p = strrchr (comment, ' '); /* find last space in file */
sscanf (p, " %d", &d4); /* read last value into d4 */
*p = 0; /* null-terminate comment */
(注意: 如果需要,您可以 check/removed comment
中的任何尾随 space,但为了我们的目的,它被省略了)
把它们放在一起你会得到这样的东西:
快速示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 128
int main (int argc, char **argv) {
if (argc < 2 ) { /* check for at least 1 argument */
fprintf (stderr, "error: insufficient input, usage: %s filename\n",
argv[0]);
return 1;
}
char line[MAXS] = {0};
char word[MAXS] = {0};
char comment[MAXS] = {0};
char *p = NULL;
size_t idx = 0;
int d1, d2, d3, d4;
float f1 = 0.0;
FILE *fp = NULL;
d1 = d2 = d3 = d4 = 0;
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file */
fprintf (stderr, "error: file open failed '%s'.", argv[1]);
return 1;
}
while (fgets (line, MAXS, fp) != NULL) /* read each line in file */
{
/* read buffer through first float */
sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);
p = strrchr (line, '/'); /* find last '/' in line */
sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value */
p = strrchr (comment, ' '); /* find last space in file */
sscanf (p, " %d", &d4); /* read last value into d4 */
*p = 0; /* null-terminate comment */
printf ("\nline : %zu\n\n %s\n", idx, line);
printf (" d1 : %d\n d2 : %d\n d3 : %d\n d4 : %d\n f1 : %.2f\n",
d1, d2, d3, d4, f1);
printf (" chained : %s\n comment : %s\n", word, comment);
idx++;
}
fclose (fp);
return 0;
}
输入
$ cat dat/strwcmt.txt
456 2 39 chained_words 62.5 // comment with more than one word 227
457 2 42 more_chained_w 64.5 // another comment 228
458 3 45 s_n_a_f_u 66.5 // this is still another comment 229
输出
$ ./bin/str_rd_mixed dat/strwcmt.txt
$ ./bin/str_rd_mixed dat/strwcmt.txt
line : 0
456 2 39 chained_words 62.5 // comment with more than one word 227
d1 : 456
d2 : 2
d3 : 39
d4 : 227
f1 : 62.50
chained : chained_words
comment : comment with more than one word
line : 1
457 2 42 more_chained_w 64.5 // another comment 228
d1 : 457
d2 : 2
d3 : 42
d4 : 228
f1 : 64.50
chained : more_chained_w
comment : another comment
line : 2
458 3 45 s_n_a_f_u 66.5 // this is still another comment 229
d1 : 458
d2 : 3
d3 : 45
d4 : 229
f1 : 66.50
chained : s_n_a_f_u
comment : this is still another comment
注意: 处理此问题的不同方法没有限制。这只是一种方法。另一种方法是将整行 标记化 成单独的单词,检查每个单词是否以数字开头(并包含 '.' 表示浮点数),然后简单地转换所有数字并连接所有根据需要使用非数字词。由你决定。你的工具箱越大,你就会看到越多的方法。