簡體   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