【问题标题】:Scan this from a text file into 2 arrays using C使用 C 将其从文本文件扫描成 2 个数组
【发布时间】:2020-06-04 08:24:00
【问题描述】:

我无法将这样的东西解析成数组。

所以我的文本文件 test.txt 有这一行: (1231212A, 1231212B) (1231212C, 321128D)

我试图将它扫描成一个数组,但它需要分成几部分

int 类型的第 1 部分应为:123

第 2 部分:12

第 3 部分:12

第 4 部分(字符):A

我需要在一行内执行 4 次

这是我的代码,但它不能正常工作

{
int nums[1][12];
char chars[1][4];
FILE *file;

file = fopen("test.txt", "r");
if (file != NULL){

fscanf(file , "%*s%3d %2d %2d %s %*s %2d %2d %2d %s%*s        %*s%3d %2d %2d %s%*s %2d %2d %2d %s%*s" 
, &nums[0][0],&nums[0][1],&nums[0][2],&chars[0][0],&nums[0][3],&nums[0][4],&nums[0][5],&chars[0] 
[1],&nums[0][6],&nums[0][7],&nums[0][8],&chars[0][2],&nums[0][9],&chars[0][10],&nums[0][11],&chars[0] 
[3]);
}

当我打印这些数组时,它们不会打印正确的数字和字符。 我需要 fscanf 部分的帮助 谢谢你

【问题讨论】:

  • 为什么在格式字符串的开头使用%*s?只需使用文字 ( 来匹配左括号。逗号和其他括号也一样。
  • 另请注意,%s 指令会读取字符直到遇到空格,因此这会将字母和逗号都读取到提供的位置。
  • 1行的二维数组有什么原因吗?
  • @DavidC.Rankin -- 我假设 OP 计划添加更多数据行。
  • 是的,看起来就是这样——只是有点奇怪。

标签: c parsing scanf


【解决方案1】:

在使用fgets() 从文件中读取 后,使用sscanf() 解析字符串,包括"%n",以检测扫描了多少。

在格式中使用 字符串文字 连接也有帮助。

//                           v---not s
#define GROUP_FMT "%3d%2d%2d%c"

int n = 0;
sscanf(line, " (" GROUP_FMT " ," GROUP_FMT " ) (" GROUP_FMT " ," GROUP_FMT " ) %n",
  &nums[0][0], &nums[0][ 1], &nums[0][ 2], &chars[0][0], 
  &nums[0][3], &nums[0][ 4], &nums[0][ 5], &chars[0][1],
  &nums[0][6], &nums[0][ 7], &nums[0][ 8], &chars[0][2],
  &nums[0][9], &nums[0][10], &nums[0][11], &chars[0][3], &n);
// Did scanning reach the %n and was that the end of the string?
if (n && line[n] == '\0') Success();
else Fail();

【讨论】:

    【解决方案2】:

    正如@chux 在他的回答中提供的那样,关键是将格式字符串与要解析的数据正确匹配,然后根据预期的转换次数严格验证返回。 格式字符串中的主要错误是您不必要地包含%*s(尝试跳过"(")和%s %*s(尝试跳过逗号)和%s%*s %*s(尝试并在几个位置跳过") ",这具有读取读数并丢弃整个第一个数字的效果,例如"(1231212A,"作为字符串,开始读取第二组数字中的值等等。

    更接近的匹配如@chux 的答案所示或简单地说:

    "(%3d%2d%2d%c, %3d%2d%2d%c) (%3d%2d%2d%c, %3d%2d%2d%c"
    

    (不同之处仅在于不提供额外的空格并且不读取消耗的字符数 - 另请注意,格式字符串中的结束 ")" 不是必需的,因为您读取了最后一个字符,例如'D' 结束转换)

    当您使用 1 行的 2D 数组时,下面的简化示例对 charsnums 使用 1D 数组,并且可以编写如下以通过 fgets() 将缓冲区传递给 @987654333 来读取@ 验证返回并输出收集的值或在解析失败时显示错误:

    #include <stdio.h>
    
    #define MAXC 1024   /* if you need a constant, #define one (or more) */
    
    int main (int argc, char **argv) {
    
        char buf[MAXC], chars[4];
        int nums[12];
        /* use filename provided as 1st argument (stdin by default) */
        FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
        if (!fp) {  /* validate file open for reading */
            perror ("file open failed");
            return 1;
        }
    
        while (fgets (buf, MAXC, fp)) { /* read line into buf with fgets() */
            /* parse with sscanf -- validate 16 conversions take place */
            if (sscanf (buf, "(%3d%2d%2d%c, %3d%2d%2d%c) (%3d%2d%2d%c, %3d%2d%2d%c",
                &nums[0], &nums[1], &nums[2], &chars[0],
                &nums[3], &nums[4], &nums[5], &chars[1],
                &nums[6], &nums[7], &nums[8], &chars[2],
                &nums[9], &nums[10], &nums[11], &chars[3]) == 16) {
                /* output result */
                printf ("%d %d %2d %c\n%d %d %2d %c\n%d %d %2d %c\n%d %d %2d %c\n",
                        nums[0], nums[1], nums[2], chars[0],
                        nums[3], nums[4], nums[5], chars[1],
                        nums[6], nums[7], nums[8], chars[2],
                        nums[9], nums[10], nums[11], chars[3]);
            }   /* or handle error */
            else
                fprintf (stderr, "error parsing data from: %s\n", buf);
        }
    
        if (fp != stdin)   /* close file if not stdin */
            fclose (fp);
    }
    

    输入文件示例

    $ cat dat/splitintoarr.txt
    (1231212A, 1231212B) (1231212C, 321128D)
    

    使用/输出示例

    $ ./bin/splitintoarr <dat/splitintoarr.txt
    123 12 12 A
    123 12 12 B
    123 12 12 C
    321 12  8 D
    

    (最终数字的输出已使用 field-width 修饰符输出,以确保列与您的数据保持对齐)

    查看所有答案,如果您还有其他问题,请告诉我们。

    【讨论】:

    • 很好的解释。请注意,格式中的最终")" 没有任何用途,使用的扫描也不会检测行中的额外数据。但不幸的是,许多人是否关心检测不良数据。
    • 我选择了"("、",", "}" 之前格式的空格,作为对可选空格的更宽松的接受。也许更好与否 - 取决于 OP 未说明目标的细节。 IAC,您的另一个不错的答案。
    • 哦,谢谢。是的,我注意到您提供的额外空白(很好的接触),但是在考虑答案时,我决定只使用输入格式的匹配(不太灵活,但对于 OP 采取它的兔子轨迹和警告更少)。有趣,很好的小问题。肯定会删除/解释最后的")"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多