繁体   English   中英

如何使用C中的数组中的元素查找和替换文本文件中的位置?

[英]How do I find and replace a position in a text file with element in an array in C?

我有两个文本文件data.txt和template.txt。 我读取并拆分data.txt中的数据并将它们存储为数组。 我的问题是将这些数据与template.txt文件一起使用,找到'$'符号并使用随后的数字作为customerData中数组的指示符。

data.txt中

Public|Jane|Q|Ms.|600|Maple Street|Your Town|Iowa|12345
Penner|Fred|R|Mr.|123|that Street|Winnipeg|MB|R3T 2N2
Gardner|Mark|E|Mr.|76|The Avenue|Toronto|ON|M5W 1E6
Acton|Hilda|P|Mrs.|66|What Blvd|Winnipeg|MB|R3T 2N2

template.txt

Welcome back, $1!
We hope that you and all the members
of the $0 family are constantly
reminding your neighbours there
on $5 to shop with us.
As usual, we will ship your order to
   $3 $1 $2. $0
   $4 $5
   $6, $7 $8

输出应该是这样的:

Welcome back, Jane!
We hope that you and all the members
of the Public family are constantly
reminding your neighbors there
on Maple Street to shop with us.
As usual, we will ship your order to
    Ms. Jane Q. Public
    600 Maple Street
    Your Town, Iowa 12345

我编写了代码但是我的大脑仍然坚持使用数组中的位置来获取template.txt。我需要帮助来解决如何在C中执行此操作? 任何贡献将不胜感激。

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

#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS   9

int main( int argc, char *argv[] )
{
  FILE *template = NULL;
  FILE *data = NULL;

  char input[INPUT_LENGTH];
  char customerData[NUM_FIELDS][FIELD_LENGTH];
  int  element = 0;
  char *next;
  char ch;

  template = fopen( "template.txt", "r" );
  if ( template != NULL )
  {
    // read in the customers until we're done
    data = fopen( "data.txt", "r" );
    if ( data != NULL )
    {

      while(fgets(input, INPUT_LENGTH,data) != NULL){
        next = strtok(input, "|"); //splitting the data stored in input by |
        while(next != NULL){
          strcpy(customerData[element],next);
          printf("%s\n", customerData[element] );  //prints the first element in the array
          next =strtok(NULL, "|");
          element++;
          while((ch=fgetc(template)) != NULL){
            if(ch == '0'){

            }else if(ch == '1'){

            }else if(ch == '2'){
                //do sth
            }else if(ch == '3'){
            }else if(ch == '4'){
            }else if(ch == '5'){
            }else if(ch == '6'){
            }else if(ch == '7'){
            }else if(ch == '8'){
            }else if(ch == '9'){
            }
          }
          /*while(fgets(input, INPUT_LENGTH,template) != NULL){
            for(int i=0; i< strlen(input); i++){
              ch= strchr(template, "$")

              ch = input[INPUT_LENGTH];
              if(ch != "$"){
                if(ch == "0"){
                  printf("%s\n", hi );

                }
              }
            }

          }*/
        }
      }






      fclose( data );
    }

    fclose( template );
  }

  return EXIT_SUCCESS;
}

有多种方法可以解决这个问题。 通过将问题分解为几个辅助函数可以使所有这些都变得更容易,这将有助于保持程序逻辑的正确性。 注意:对于任何一段代码都是如此,但对于这段代码尤其如此)。

与每个客户相关联的信息集合的数据处理可以由包含每个字段的成员的struct来处理。 (虽然每个字段的大小可以更加狭窄,但是30字段大小很好)例如,为FLDSZ = 30声明一个常量,您可以为您的信息创建一个类似于以下内容的结构:

typedef struct {
    char last[FLDSZ];
    char first[FLDSZ];
    char mi[FLDSZ];
    char sal[FLDSZ];
    char street[FLDSZ];
    char streetno[FLDSZ];
    char city[FLDSZ];
    char state[FLDSZ];
    char zip[FLDSZ];
} sp;

(理想情况下你想动态分配指针的一些初始数目为结构,以填充和realloc需要。对于这个例子的目的,包含在阵列中的静态数量是罚款)

要开始存储数据,您需要一种方法将行划分为各种标记。 strtok在这里很理想。 您只需要读取每一行,对其进行标记,并将结果字符串存储为正确的成员。 使用结构数组,除了编写将单个标记存储为正确成员的方法之外,还需要跟踪单个结构索引。 这是第一个辅助函数可以使生活更轻松的地方。 例如,您可以使用类似于以下内容的方式完成数据结构的整个读取/填充:

char buf[MAXC] = {0};
sp s[MAXS];
....
while (fgets (buf, MAXC, ifp)) { /* read each line of data */
    char *p;
    size_t idx = 0; /* tokenize/save in struct 's[n]' */
    for (p = strtok (buf, "|"); p; p = strtok (NULL, "|\n")) {
        fillsp (&s[n], p, &idx);  /* assign to correct member */
    }
    if (++n == MAXS) { /* limit reached */
        fprintf (stderr, "MAXS structs filled.\n");
        break;
    }
}

(其中ifp是您的输入文件流指针n您的struct索引)

帮助函数fillsp是关键。 它采用struct sp地址 ,指向当前标记的指针,以及指向当前成员索引 idx的指针。 根据idx的值,通过if-then-else字符串或更好的switch语句,您可以使用每个标记协调正确的成员。 类似于以下的东西适合这里:

/* store 'p' in correct stuct 's' member based on index 'idx' */
void fillsp (sp *s, const char *p, size_t *idx)
{
    switch (*idx) {
        case 0 :
            strncpy (s->last, p, FLDSZ);
            if (s->last[FLDSZ - 1] != 0) s->last[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 1 :
            strncpy (s->first, p, FLDSZ);
            if (s->first[FLDSZ - 1] != 0) s->first[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 2 :
            s->mi[0] = s->mi[1] = 0;
            *(s->mi) = *p;
            (*idx)++;
            break;
        case 3 :
            strncpy (s->sal, p, FLDSZ);
            if (s->sal[FLDSZ - 1] != 0) s->sal[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 4 :
            strncpy (s->streetno, p, FLDSZ);
            if (s->streetno[FLDSZ - 1] != 0) s->streetno[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 5 :
            strncpy (s->street, p, FLDSZ);
            if (s->street[FLDSZ - 1] != 0) s->street[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 6 :
            strncpy (s->city, p, FLDSZ);
            if (s->city[FLDSZ - 1] != 0) s->city[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 7 :
            strncpy (s->state, p, FLDSZ);
            if (s->state[FLDSZ - 1] != 0) s->state[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 8 :
            strncpy (s->zip, p, FLDSZ);
            if (s->zip[FLDSZ - 1] != 0) s->zip[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        default :
            fprintf (stderr, "error: index outside allowed 0-8.\n");
            exit (EXIT_FAILURE);
    }
}

注意:当找到正确的大小写时会更新idx默认情况下会警告无效索引,但除了强制终止之外,还应该添加strlen检查)。

存储数据后,下一个任务是简单地读取模板文件,并用结构中相应的字段替换'$X'格式占位符。 需要注意的一点是,每次读取后都需要rewind 模板文件指针'tfp' ),以便再次用于下一个客户。 在这里,帮助函数再次有帮助。 显示每个客户的欢迎信息的逻辑可以很简单:

for (i = 0; i < n; i++)     /* show welcome for each */
    welcome (&s[i], tfp);

注意:实际上,您将查找客户名称,然后将该地址传递给welcome函数,但是对于此示例,每个都将打印)

welcome函数中解析模板的每一行时, strchr函数提供了一种简单的方法来检查定位任何给定行中的任何'$' 通过使用几个字符指针,您可以轻松遍历每一行并定位/替换每个格式说明符。 要创建要输出的实际行,可以使用strcatstrncat 例如,您可以使用类似于以下内容的welcome

void welcome (sp *s, FILE *tfp)
{
    char buf[MAXC] = {0};
    while (fgets (buf, MAXC, tfp)) {
        char *p = buf, *ep;
        char obuf[MAXC] = {0};
        while (*p && (ep = strchr (p, '$'))) {
            strncat (obuf, p, ep++ - p);
            strcat  (obuf, rtnmemb (s, *ep++ - '0'));
            p = ep;
        }
        strcat (obuf, p);
        printf ("%s", obuf); /* relies on trailing '\n' from read */
    }
    putchar ('\n');
    rewind (tfp);
}

welcome使用的最后一个辅助函数是rtnmemb用于返回'$'后面的字符标识的成员 注意:由于您将数字作为字符读取,因此需要从ASCII值中减去'0'以将其转换为数值。) rtnmemb的实现可能如下所示:

/* return correct member of struct 's' based on 'idx' */
char *rtnmemb (sp *s, size_t idx)
{
    switch (idx) {
        case 0 : return s->last; break;
        case 1 : return s->first; break;
        case 2 : return s->mi; break;
        case 3 : return s->sal; break;
        case 4 : return s->streetno; break;
        case 5 : return s->street; break;
        case 6 : return s->city; break;
        case 7 : return s->state; break;
        case 8 : return s->zip; break;
        default : printf ("error: requested member outside allowed 0-8.\n");
    }
    return NULL;
}

将拼图的所有部分组合在一起,您可以执行以下操作:

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

/* constants (file size, max struct, max char) */
enum { FLDSZ = 30, MAXS = 64, MAXC = 128 };

typedef struct {
    char last[FLDSZ];
    char first[FLDSZ];
    char mi[FLDSZ];
    char sal[FLDSZ];
    char street[FLDSZ];
    char streetno[FLDSZ];
    char city[FLDSZ];
    char state[FLDSZ];
    char zip[FLDSZ];
} sp;

void fillsp (sp *s, const char *p, size_t *idx);
char *rtnmemb (sp *s, size_t idx);
void welcome (sp *s, FILE *tfp);

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

    char buf[MAXC] = {0};
    sp s[MAXS];
    size_t i, n = 0;  /* input, template, output streams */
    FILE *ifp = argc > 1 ? fopen (argv[1], "r") : stdin;
    FILE *tfp = fopen (argc > 2 ? argv[2] : "../dat/template.txt", "r");
    FILE *ofp = argc > 3 ? fopen (argv[3], "w") : stdout;

    if (!ifp || !tfp || !ofp) { /* validate streams open */
        fprintf (stderr, "error: file open failed.\n");
        return 1;
    }

    while (fgets (buf, MAXC, ifp)) { /* read each line of data */
        char *p;
        size_t idx = 0; /* tokenize/save in struct 's[n]' */
        for (p = strtok (buf, "|"); p; p = strtok (NULL, "|\n")) {
            fillsp (&s[n], p, &idx);
        }
        if (++n == MAXS) { /* limit reached */
            fprintf (stderr, "MAXS structs filled.\n");
            break;
        }
    }

    for (i = 0; i < n; i++)     /* show welcome for each */
        welcome (&s[i], tfp);

    if (ifp != stdin)  fclose (ifp);    /* close files */
    if (ofp != stdout) fclose (ofp);
    fclose (tfp);

    return 0;
}

/* store 'p' in correct stuct 's' member based on index 'idx' */
void fillsp (sp *s, const char *p, size_t *idx)
{
    switch (*idx) {
        case 0 :
            strncpy (s->last, p, FLDSZ);
            if (s->last[FLDSZ - 1] != 0) s->last[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 1 :
            strncpy (s->first, p, FLDSZ);
            if (s->first[FLDSZ - 1] != 0) s->first[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 2 :
            s->mi[0] = s->mi[1] = 0;
            *(s->mi) = *p;
            (*idx)++;
            break;
        case 3 :
            strncpy (s->sal, p, FLDSZ);
            if (s->sal[FLDSZ - 1] != 0) s->sal[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 4 :
            strncpy (s->streetno, p, FLDSZ);
            if (s->streetno[FLDSZ - 1] != 0) s->streetno[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 5 :
            strncpy (s->street, p, FLDSZ);
            if (s->street[FLDSZ - 1] != 0) s->street[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 6 :
            strncpy (s->city, p, FLDSZ);
            if (s->city[FLDSZ - 1] != 0) s->city[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 7 :
            strncpy (s->state, p, FLDSZ);
            if (s->state[FLDSZ - 1] != 0) s->state[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        case 8 :
            strncpy (s->zip, p, FLDSZ);
            if (s->zip[FLDSZ - 1] != 0) s->zip[FLDSZ - 1] = 0;
            (*idx)++;
            break;
        default :
            fprintf (stderr, "error: index outside allowed 0-8.\n");
            exit (EXIT_FAILURE);
    }
}

/* return correct member of struct 's' based on 'idx' */
char *rtnmemb (sp *s, size_t idx)
{
    switch (idx) {
        case 0 : return s->last; break;
        case 1 : return s->first; break;
        case 2 : return s->mi; break;
        case 3 : return s->sal; break;
        case 4 : return s->streetno; break;
        case 5 : return s->street; break;
        case 6 : return s->city; break;
        case 7 : return s->state; break;
        case 8 : return s->zip; break;
        default : printf ("error: requested member outside allowed 0-8.\n");
    }
    return NULL;
}

void welcome (sp *s, FILE *tfp)
{
    char buf[MAXC] = {0};
    while (fgets (buf, MAXC, tfp)) {
        char *p = buf, *ep;
        char obuf[MAXC] = {0};
        while (*p && (ep = strchr (p, '$'))) {
            strncat (obuf, p, ep++ - p);
            strcat  (obuf, rtnmemb (s, *ep++ - '0'));
            p = ep;
        }
        strcat (obuf, p);
        printf ("%s", obuf);
    }
    putchar ('\n');
    rewind (tfp);
}

产量

$ ./bin/str_template ../dat/data.txt
Welcome back, Jane!
We hope that you and all the members
of the Public family are constantly
reminding your neighbours there
on Maple Street to shop with us.
As usual, we will ship your order to
   Ms. Jane Q. Public
   600 Maple Street
   Your Town, Iowa 12345

Welcome back, Fred!
We hope that you and all the members
of the Penner family are constantly
reminding your neighbours there
on that Street to shop with us.
As usual, we will ship your order to
   Mr. Fred R. Penner
   123 that Street
   Winnipeg, MB R3T 2N2

Welcome back, Mark!
We hope that you and all the members
of the Gardner family are constantly
reminding your neighbours there
on The Avenue to shop with us.
As usual, we will ship your order to
   Mr. Mark E. Gardner
   76 The Avenue
   Toronto, ON M5W 1E6

Welcome back, Hilda!
We hope that you and all the members
of the Acton family are constantly
reminding your neighbours there
on What Blvd to shop with us.
As usual, we will ship your order to
   Mrs. Hilda P. Acton
   66 What Blvd
   Winnipeg, MB R3T 2N2

看看问题的解决方法。 使用switch语句替换if-then-else语句的长链通常会带来好处。 两者都是可以接受的,这适用于您的问题的任何不同方法。 只要任何方法正确处理数据,可读且合理有效并提供正确的输出,最终都是品味问题。 如果您对此方法有任何疑问,请与我们联系。

我认为这可以通过更简单的方式完成:

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

#define FLDMAX          30

// docust -- process single customer line
void
docust(FILE *ftmpl,char *buf)
{
    int fldcnt;
    char *bp;
    char *cp;
    int chr;
    int prev;
    char *fields[FLDMAX];

    fputc('\n',stdout);

    // split customer line into fields
    fldcnt = 0;
    bp = buf;
    while (1) {
        cp = strtok(bp,"|");
        bp = NULL;

        if (cp == NULL)
            break;

        fields[fldcnt++] = cp;

        if (fldcnt >= FLDMAX)
            break;
    }

    rewind(ftmpl);

    // output the form letter
    prev = EOF;
    while (1) {
        chr = fgetc(ftmpl);
        if (chr == EOF)
            break;

        prev = chr;

        // output ordinary char
        if (chr != '$') {
            fputc(chr,stdout);
            continue;
        }

        // get field designator (e.g. $3)
        chr = fgetc(ftmpl);

        // point to correct customer field
        chr -= '0';
        if (chr >= fldcnt)
            continue;
        cp = fields[chr];

        fputs(cp,stdout);
    }

    // malformed template file (e.g. has no newline at end)
    if (prev != '\n')
        fputc('\n',stdout);
}

int
main(int argc,char **argv)
{
    FILE *ftmpl;
    FILE *fcust;
    char *cp;
    char buf[5000];

    fcust = fopen("data.txt","r");
    ftmpl = fopen("template.txt","r");

    while (1) {
        cp = fgets(buf,sizeof(buf),fcust);
        if (cp == NULL)
            break;

        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;

        docust(ftmpl,buf);
    }

    fclose(fcust);
    fclose(ftmpl);

    return 0;
}

更新:

这是一个更接近我将为“生产级”应用程序做的版本。 这主要基于彼得在下面的评论

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

typedef unsigned int u32;

// check for value within a given range
#define RANGE(_val,_lo,_hi) \
    (((_val) >= (_lo)) && ((_val) <= (_hi)))

#define FLDMAX          30              // maximum number of fields

// all options
#define OPTALL(_cmd) \
    _cmd(ERRSPLIT,0,"too many fields in customer record") \
    _cmd(ERRSYN,1,"malformed $x in template") \
    _cmd(ERRFIELD,2,"template $x too large") \
    _cmd(ERRNL,3,"template missing final newline") \
    _cmd(BADMONEY,4,"malformed money amount")

// define option symbols
#define _OPTDEF(_sym,_val,_reason) \
    OPT_##_sym = 1u << ((_val) + 16),
enum {
    OPTALL(_OPTDEF)
};

#define OPTMSK      0xFFFF0000
#define OPTVAL      0x0000FFFF

// option control
struct opt {
    u32 opt_val;                        // option value
    const char *opt_tag;                // option name
    const char *opt_reason;             // option explanation
};

// option table
#define _OPTGEN(_sym,_val,_reason) \
    { .opt_val = OPT_##_sym, .opt_tag = #_sym, .opt_reason = _reason },
struct opt opt_table[] = {
    OPTALL(_OPTGEN)
    { . opt_tag = NULL }
};

// abort
#define sysfault(_fmt...) \
    do { \
        fprintf(stderr,_fmt); \
        exit(1); \
    } while (0)

// xfopen -- open file
FILE *
xfopen(const char *file,const char *mode)
{
    FILE *xf;

    xf = fopen(file,mode);
    if (xf == NULL)
        sysfault("xfopen: unable to open '%s' -- %s\n",file,strerror(errno));

    return xf;
}

// xfclose -- close file
FILE *
xfclose(FILE *xf)
{

    if (xf != NULL) {
        fclose(xf);
        xf = NULL;
    }

    return xf;
}

// showerr -- show errors
void
showerr(u32 err)
{
    struct opt *opt;

    err &= OPTMSK;

    if (err != 0) {
        for (opt = opt_table;  opt->opt_tag != NULL;  ++opt) {
            if (err & opt->opt_val)
                fprintf(stderr,"showerr: %s -- %s\n",
                    opt->opt_tag,opt->opt_reason);
        }
        sysfault("showerr: aborting ...\n");
    }
}

// getfld -- get field designator
// RETURNS: field number (-1 means malformed (e.g. $X))
int
getfld(FILE *ftmpl)
{
    int chr;
    int acc;

    // assume malformed
    acc = -1;

    while (1) {
        chr = fgetc(ftmpl);
        if (chr == EOF)
            break;

        if (! RANGE(chr,'0','9')) {
            ungetc(chr,ftmpl);
            break;
        }

        if (acc < 0)
            acc = 0;
        acc *= 10;

        chr -= '0';
        acc += chr;
    }

    return acc;
}

// domoney -- output a monetary amount
// RETURNS: error mask
u32
domoney(FILE *fout,FILE *ftmpl)
{
    int chr;
    int cents;
    u32 opt;

    opt = 0;

    fputc('$',fout);

    // get dollars
    while (1) {
        chr = fgetc(ftmpl);

        if (chr == EOF) {
            opt |= OPT_BADMONEY;
            break;
        }

        fputc(chr,fout);

        if (chr == '.')
            break;

        // got something like "$$23x"
        if (! RANGE(chr,'0','9')) {
            opt |= OPT_BADMONEY;
            break;
        }
    }

    // get cents
    for (cents = 1;  cents <= 2;  ++cents) {
        if (opt != 0)
            break;

        chr = fgetc(ftmpl);

        // got something like "$$23."
        if (chr == EOF) {
            opt |= OPT_BADMONEY;
            break;
        }

        fputc(chr,fout);

        // got something like "$$23.x"
        if (! RANGE(chr,'0','9')) {
            opt |= OPT_BADMONEY;
            break;
        }
    }

    return opt;
}

// dosplit -- split customer line into fields
// RETURNS: number of fields (-1=overflow)
int
dosplit(char **fields,char *buf)
{
    int fldcnt;
    char *bp;
    char *cp;

    fldcnt = 0;
    bp = buf;

    while (1) {
        cp = strtok(bp,"|");
        bp = NULL;

        if (cp == NULL)
            break;

        fields[fldcnt++] = cp;

        if (fldcnt > FLDMAX) {
            fldcnt = -1;
            break;
        }
    }

    return fldcnt;
}

// docust -- process single customer line
// RETURNS: options
u32
docust(FILE *fout,FILE *ftmpl,char *buf)
{
    int chr;
    int prev;
    int fldcnt;
    int fldidx;
    int fldused;
    char *cp;
    char *fields[FLDMAX];
    u32 opt;

    opt = 0;
    fldidx = 0;
    fldused = -1;

    // split customer line into fields
    fldcnt = dosplit(fields,buf);
    if (fldcnt < 0)
        opt |= OPT_ERRSPLIT;

    rewind(ftmpl);

    fputc('\n',fout);

    // output the form letter
    prev = EOF;
    while (1) {
        chr = fgetc(ftmpl);
        if (chr == EOF)
            break;

        prev = chr;

        // output ordinary char
        if (chr != '$') {
            fputc(chr,fout);
            continue;
        }

        // check for '$$' for literal '$' for money designator
        // NOTE: this is vast overkill, based on the problem description
        chr = fgetc(ftmpl);
        if (chr == '$') {
            opt |= domoney(fout,ftmpl);
            continue;
        }
        ungetc(chr,ftmpl);

        // get field designator (e.g. $3)
        fldidx = getfld(ftmpl);

        // malformed designator (e.g. $X)
        if (fldidx < 0) {
            opt |= OPT_ERRSYN;
            continue;
        }

        // point to correct customer field
        if (fldidx >= fldcnt) {
            opt |= OPT_ERRFIELD;
            continue;
        }
        cp = fields[fldidx];

        // remember the largest field index we actually use
        if (fldidx > fldused)
            fldused = fldidx;

        fputs(cp,fout);
    }

    // malformed template file (e.g. has no newline at end)
    // technically an error but we can handle it
    if (prev != '\n') {
        fputc('\n',fout);
        opt |= OPT_ERRNL;
    }

    opt |= fldused;

    return opt;
}

// check_tmpl -- validate form letter template file
// RETURNS: the maximum field index used by the template file
int
check_tmpl(FILE *fout,FILE *ftmpl)
{
    int fldidx;
    char *bp;
    u32 err;
    char buf[5000];

    bp = buf;
    for (fldidx = 0;  fldidx < FLDMAX;  ++fldidx)
        bp += sprintf(bp,"|fld%d",fldidx);

    err = docust(fout,ftmpl,buf + 1);
    showerr(err);

    // the maximum index we actually used
    fldidx = err & OPTVAL;

    return fldidx;
}

// check_cust -- validate customer entries
void
check_cust(FILE *fout,FILE *fcust,int fldused)
{
    int fldcnt;
    u32 err;
    char *cp;
    char buf[5000];
    char *fields[FLDMAX];

    rewind(fcust);

    err = 0;

    while (1) {
        cp = fgets(buf,sizeof(buf),fcust);
        if (cp == NULL)
            break;

        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;

        fldcnt = dosplit(fields,buf);
        if (fldcnt < 0)
            err |= OPT_ERRSPLIT;

        if (fldcnt != (fldused + 1))
            err |= OPT_ERRFIELD;

        showerr(err);
    }
}

// main -- main program
int
main(int argc,char **argv)
{
    FILE *ftmpl;
    FILE *fcust;
    FILE *fout;
    int fldused;
    char *cp;
    char buf[5000];

    fcust = xfopen("data.txt","r");
    ftmpl = xfopen("template.txt","r");

    // pre-validate input files
    fout = xfopen("/dev/null","w");
    fldused = check_tmpl(fout,ftmpl);
    check_cust(fout,fcust,fldused);
    fout = xfclose(fout);

    rewind(fcust);
    while (1) {
        cp = fgets(buf,sizeof(buf),fcust);
        if (cp == NULL)
            break;

        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;

        docust(stdout,ftmpl,buf);
    }

    fcust = xfclose(fcust);
    ftmpl = xfclose(ftmpl);

    return 0;
}

彼得的评论:

但+1是实现敏感表查找的唯一答案,而不是在交换机上浪费代码

如果已经说明了问题允许multichar现场指示符(例如$10 ),这对每个人来说都是显而易见的。 在更新的代码中,这是在getfld实现的。 但是,在原文中,我只是假设它,因为它使解决方案更容易

如果(chr >= fldcnt)你确定吗? 或者也许你假设在输入中没有任何错误的'$'字符,比如$A

是。 在原始版本中,只检查一个太大的字段编号,而不是检查格式错误的字段指示符,如$X

基于简单的问题陈述,我们可以假设模板形成良好。 对于生产代码,我们应该检查这个,就像我使用check_tmplcheck_cust等。 人。 但是,请注意需要多少额外代码才能真正进行彻底检查[并且可以更加彻底地进行检查]。

或者也许设置一下,所以$$打印一个$ ,允许货币,如$15.25

很公平。 根据问题陈述,这有点过分,但[只是为了表明它可以完成]我已经在domoney添加了它

如果检查失败,如果没有替换,则按字面打印$c

不。如果我们发现一个格式错误的指示符,我们希望这是一个很难的错误。 如果模板文件格式错误,我们希望中止而不是打印数百万个有错误的套用信函。 这就是我添加check_tmpl函数的原因。

发送坏信的纸张和邮资[或电子邮件或即时消息的成本]的成本可能很高。 更不用说损害公司的声誉了。

因为客户文件就像一个数据库,我们可以而且应该执行严格的检查,因为可能已经预先检查了数据库输入。

如果任何客户记录格式错误,该程序将中止。 一个改进只是标记和跳过不良客户记录,但这取决于哪种公司“政策”将适用于这种情况。

我知道这篇文章很老但我遇到了同样的问题,我将为未来的读者分享我的代码。 这就是我完成它的方式。 我没有做任何复杂的事情。 在解析数据并将其存储到customerData ,可以通过读取每个字符将数据叠加到数组索引上。

    rewind( template );
    while ( fgets( input, INPUT_LENGTH, template ) != NULL )
    {
      // Process the input one character at a time looking for variables to replace with customerData
      element = 0;
      ch = input[element];

      while(ch) {
        if(ch != '$') {
          printf("%c", ch);
        } else {
          element++;
          ch = input[element];
          printf("%s", customerData[atoi( &ch)]);
        }
        element++;
        ch = input[element];
      }
     }
     printf("\n");

好的..你应该做类似的事情:

 element++;
 } /* finish processing ONE line and gather all array
 /*  open the file now. not before */
 template = fopen( "template.txt", "r" );
 while((ch=fgetc(template)) != NULL){
      if ( ch == '$' ) {
         char next=fgetc(template));
         if ( next == '1' ) {
              printf("%s ",customerData[1]);
         ...

      } else { 
        printf("%c",ch); /* just print as it is */
      }
 printf("\n");
 fclose(template);
/*process next line in outer while loop */

如果您理解了上述内容,您可以在将来执行此操作:(i)将模板文件只读入一个长字符串(char [300])并重复使用for (i=0;i<strlen(template_string);i++)

(ii)你可以理解'9' - '0'将导致int 0,'8' - '3'将导致int 5.所以你可以使用int col = next - '0'; printf("%s ", customerData[col]) int col = next - '0'; printf("%s ", customerData[col]) (Barmer告诉)

祝你好运。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM