【问题标题】:How to make a program work on different text files in C如何使程序在C中的不同文本文件上工作
【发布时间】:2015-02-14 19:02:30
【问题描述】:

我正在尝试使用命令行参数并在 C 中解析文本文件。基本上我希望能够输入两个数字,例如 1 和 4,并让它读取文本文件的一列然后打印它到标准输出。我希望能够做这样的事情:

PID   TTY        TIME     CMD
449   ttys000    0:00.35 -bash
1129  ttys001    0:00.35 -bash
25605 ttys001    0:00.15  vi    prog.c
6132  ttys002    0:00.11 -bash
6208  ttys002    0:00.03  vi    test

然后做:

./your_prog 1 2 5 < data.txt 

PID   TTY
449   ttys000
1129  ttys001
25605 ttys001 prog.c
6132  ttys002 
6208  ttys002 test

我已经让程序能够根据命令行参数打印出正确的列。但是,我真正的问题是,如果给我一个包含未知数量的列的文本文件并被要求对其进行处理,我将如何使它适用于大多数(如果不是所有)这种格式的文本文件?

这是我目前的代码:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv){
int col1, col2;
int size = 512;
char ch[size];
char *temp[size];
char *my_array[size];
int field_count = 0;

char *token;

if(argc == 1){
  fprintf(stderr, "I need more!\n");
  return 1;
}
else{
  //test to see what is stored
  int i;
  for (i = 0; i < argc; i++) {
    printf("argv[%d] = %s\n", i, argv[i]);   
  }

if(sscanf(argv[1], "%d", &col1) != 1) return 1;
if(sscanf(argv[2], "%d", &col2) != 1) return 1;   

while(fgets(ch, size, stdin) != NULL){
  //get 1st token
  token = strtok(ch, " ");
  while(token != NULL){
    //printf(" %s", token);
    temp[i++] = token;
    my_array[field_count] = token;
    field_count++;
    token = strtok(NULL, " ");
  } 
  if(col1 == 1){
    printf("%s\n", my_array[0]);
  }  
} 
  return 0;   
}
}

【问题讨论】:

  • 这已经用cut linux.die.net/man/1/cut完成了
  • 仅供参考,您尝试做的正是cut 所做的。见linux.die.net/man/1/cut
  • 这是昨天的问题 (stackoverflow.com/questions/28505929/…),我建议您计算每一行的字段并保留与所需列号匹配的字段。然而,您并没有在每个文本行的开头重置field_count。你快到了……但如果你不知道文件包含什么,你怎么知道要捕获哪些列?也许命令行参数应该指定列标题文本,然后解析第一行以确定您希望在后续行中保留哪些列numbers
  • 变量'size'应该是#define size (512)
  • 顺便说一句,请注意您的第一个测试if(argc == 1)。你想要两个列号,所以测试应该是if(argc != 3)

标签: c performance tokenize


【解决方案1】:

我注意到您正试图通过将 strtok() 返回的指针存储在一个数组中来捕获该字段,但是该指针的数据是瞬态的:您需要一个字符串数组来将实际文本复制到其中。我已经重新设计并简化了您相当成功的尝试,请尝试仅打印捕获的字段 - 您的下一步可能是将它们写入文件。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE    512                     // for buffer size

void fatal(char *msg) {                     // easy  & informative getout
    printf("%s\n", msg);
    exit (1);
}

int main(int argc, char **argv){
    int col1, col2;
    char ch[BUF_SIZE];
    int field_count;
    char delims[] = " \t\n";                // might be tabs and newlines
    char *token;

    if(argc != 3)                           // check exact number of args
        fatal ("I need more!");
    if(sscanf(argv[1], "%d", &col1) != 1)
        fatal ("Bad first argument");
    if(sscanf(argv[2], "%d", &col2) != 1)
        fatal ("Bad second argument");
    printf("Capturing fields %d and %d\n", col1, col2);

    while(fgets(ch, BUF_SIZE, stdin) != NULL){
        field_count = 1;                    // reset field count
        printf("Fields captured:");
        token = strtok(ch, delims);
        while(token != NULL){
            if (field_count == col1 || field_count == col2)
                printf(" %s", token);
            field_count++;
            token = strtok(NULL, delims);
        }
        printf("\n");
    } 
    return 0;   
}

【讨论】:

  • 这个程序运行时,至少对于上面的示例.txt文件,它有5列数据。如果我只想打印第一列,那么我会传递 1,或者如果我想要前两个,那么我会在命令行参数中传递 1 2 等等。我只想打印到标准输出,而不是文本文件。那么按照上面的方式做,就可以做到这一点呢?
  • 按照您的要求,这坚持两列。如果您只想要一列,请输入runprog 1 1,即带有两个相同的参数。如果您想要可变数量的列,只需处理至少一个参数并构建一个列号数组,其中包含要捕获的字段总数(如数组中)。然后在strtok() 循环中,针对该数组中的所有列/字段编号测试field_count,而不是您要求的特定两列。听:一步一步,你会到达那里。但是你需要自己写。
  • 谢谢。对不起,如果这些是愚蠢的问题。我习惯用 C# 编写,所以 C 有点难以理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
相关资源
最近更新 更多