【问题标题】:Separating string and integer using delimiter使用分隔符分隔字符串和整数
【发布时间】:2017-09-02 14:03:37
【问题描述】:

早安,

所以目前我有这个文件并包含:实际文件是这样的

1,name A. lname2,Das F. Esd3,Frsas A. Casdfre4,Rsadna P. Tsdaas5,Asadla C. Toasdtino6,Aasdel P. Gasdla7,Masda Isable A. Milasdroso8,Niasdkie T. Niasdemus9,Evasdn A. Vasdueva10,Geasdlyn C. Iasdncio11,Aasdr Leasdma12,Neasdio A. Maasdbale

我无法输出,这是我当前的代码

printf("\nID\tName\n");    
while(fscanf(load, "%[^,],%[^1-9]", faculty[counter].id, faculty[counter].name)!=EOF) {  
    printf("%s\t%s", faculty[counter].id, faculty[counter].name);


输出是这样的:

ID  Name    
1   asdasd    
2   asdas   
3   asdsad4     othername    
5   asdsad   
6   asdasda    
7   sdfsdf    
8   sadsad   
9   asdsad       
10  asdas    
11  asdsad12    asdas       
4,12 has invalid position.

输出应该是一个范围:

1  ID   Name    
1   asdasd    
2   asdas   
3   asdsad    
4   othername    
5   asdsad   
6   asdasda    
7   sdfsdf    
8   sadsad   
9   asdsad       
10  asdas    
11  asdsad    
12  asdas    

可能是什么问题?这是我第一次使用这样的分隔符,你能解释一下有什么问题吗?谢谢!

【问题讨论】:

  • 请对代码块、输出和文件内容使用正确的格式。 @Someprogrammerdude 试图修复它,但您的编辑将其改回。 Eimantas 应用的最新修复。
  • 代码已修复,抱歉
  • 你在fscanf中使用正则表达式;这是不正确的,它只理解格式字符串。
  • 如果你想稳健地读取这样的输入,使用fscanf,这可能非常非常困难,尤其是如果输入有奇怪的皱纹,或者如果你想优雅地处理输入错误。一般来说,使用(f)scanf 以外的技术读取输入要容易得多(从长远来看)。起初这似乎更难,因为*f)scanf 似乎 非常方便,而且这是所有入门教科书向您展示的,好像它是进行输入的 方式。但事实并非如此,您越早了解其他技术并放弃 (f)scanf,您作为 C 程序员就会越快乐、越高效。
  • @HennoBrandsma 实际上,scanf 系列确实支持非常有限的类似正则表达式的功能,使用 %[...] 说明符,如显示。

标签: c scanf delimiter


【解决方案1】:

把格式改成这样:

printf("\nID\tName\n");    
while (fscanf(load, " %[0-9], %[^0-9]", faculty[counter].id, faculty[counter].name) == 2) {  
    printf("%s\t%s\n", faculty[counter].id, faculty[counter].name);
    ...
    counter++;
}

请注意,您还应该将要存储的最大字符数传递给目标数组,以避免潜在的缓冲区溢出。

但是请注意,问题中发布的示例输出与代码片段不一致:您没有以printf 格式输出换行符并确认数据文件中没有换行符,输出中的换行符在哪里从哪里来?

你能用假名制作一个显示问题的测试文件吗?还要发布失败的完整代码。结构定义也很重要。如果没有精确的数据和代码,很难设置诊断。

【讨论】:

  • 仅显示 1 个输出
  • 您显示的输出与您发布的文件内容不一致。数字后面总是有逗号吗?该文件是否包含换行符?
  • 是的,就是这样,数字后面有逗号,但是lastname后面没有逗号,没有换行符 1,fistname A. lastname2,firstname F. lastname 我只是随机添加了一些字符,因为它包含真实姓名,对不起
  • @JesusEnriqueBuencamino 我认为您需要修复您的输入。您说“数字后有逗号”,但问题似乎是2Das F. Esd 之间没有逗号。
  • 对不起,我再次编辑帖子,2和Das F之间应该有一个逗号
【解决方案2】:

在这种情况下,单独使用 fscanf 读取可以工作,但缺乏通过一次读取整行然后使用 sscanf 解析行或简单地向下移动一对字符指针来实现的稳健性挑选出idname 对的行。

要在您发布的行上使用fscanf 作为输入,您可以在重复调用fscanf 时使用"%d,%[^0-9]"格式说明符。 (如果名称长于数组大小,您应该提供一个 field-width 修饰符以防止溢出)。例如,您可以执行以下操作来获取每个 idname 对(在下面的示例中只是输出):

#include <stdio.h>

enum { MAXNM = 64 };   /* constant for max characters in name */

int main (int argc, char **argv) {

    int id;
    char name[MAXNM] = "";
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read each 'id,name' pair (name cannot include digits) */
    while (fscanf (fp, "%d,%63[^0-9]", &id, name) == 2)
            printf ("%3d    %s\n", id, name);

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

使用/输出示例

$ ./bin/rd_num_name <dat/num_names.txt
  1    name A. lname
  2    Das F. Esd
  3    Frsas A. Casdfre
  4    Rsadna P. Tsdaas
  5    Asadla C. Toasdtino
  6    Aasdel P. Gasdla
  7    Masda Isable A. Milasdroso
  8    Niasdkie T. Niasdemus
  9    Evasdn A. Vasdueva
 10    Geasdlyn C. Iasdncio
 11    Aasdr Leasdma
 12    Neasdio A. Maasdbale

如果您想使用带有fgetsgetline面向行的 输入来读取整行,然后从保存整行的缓冲区中解析每个idname ,您可以执行以下操作。读取整行,然后解析的好处是,它将读取与解析分离,允许您验证两者。此外,您的读取不会因输入格式的细微变化而匹配失败

在这里,使用sscanf 并利用%n 格式说明符 来确定每次调用sscanf 所消耗的字符数,您可以将指针向下移动以选择@ 987654339@ 和 name 对,例如

#include <stdio.h>

enum { MAXNM = 64, MAXLN = 512 };   /* max name & line constants */

int main (int argc, char **argv) {

    int id;
    char name[MAXNM] = "",
        line[MAXLN] = "",
        *p = line;          /* pointer to line to walk string */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (line, sizeof line, fp))   /* read each line / validate */
    {
        int offset = 0;                     /* number of char processed  */
        while (sscanf (p, "%d,%63[^0-9]%n", &id, name, &offset) == 2) {
            printf ("%3d    %s\n", id, name);
            p += offset;                    /* advance to next id,name */
        }
    }

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

注意:输出是一样的。

【讨论】:

    猜你喜欢
    • 2014-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 2017-05-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多