簡體   English   中英

將連續的標簽讀為空字段fscanf

[英]read consecutive tabs as empty field fscanf

我有一個文件,其中某些字段由制表符分隔。 一行中總會有12個制表符,某些制表符是連續的,表示空字段。 我想使用fscanf將連續的標簽讀取為空字段並將它們存儲在結構中。 但似乎有一個問題。 這是我的檔案:

   usrid    User Id 0   15  string  d   k   y   y           0   0

當我嘗試使用fscanf讀取時,選項卡后面的選項卡不會被識別為空字段,並且數據存儲在錯誤的結構字段中。 處理問題的最佳方法是什么?

fscanf是一個非首發。 讀取空字段的唯一方法是使用"%c"來讀取分隔符(這需要您事先知道哪些字段是空的 - 不是很有用)否則,根據所使用的格式說明符fscanf會消耗掉tabs作為前導空格或遇到匹配的失敗輸入失敗

繼續注釋,為了基於可能分隔空字段的分隔符進行標記化,您將需要使用strsep因為strtok將連續分隔符視為一個。

雖然你的字符串有些不清楚tabs的位置,但是使用strsep進行標記的簡短示例如下所示。 請注意, strsep將指針指針作為其第一個參數,例如

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

int main (void) {

    int n = 0;
    const char *delim = "\t\n";
    char *s = strdup ("usrid\tUser Id 0\t15\tstring\td\tk\ty\ty\t\t\t0\t0"),
        *toks = s,   /* tokenize with separate pointer to preserve s */
        *p;

    while ((p = strsep (&toks, delim)))
        printf ("token[%2d]: '%s'\n", n++ + 1, p);

    free (s);
}

注意:因為strsep會修改字符串指針所持有的地址,所以你需要保留一個指向s開頭的指針,以便在不再需要它時可以釋放它 - 感謝JL)

示例使用/輸出

$ ./bin/strtok_tab
token[ 1]: 'usrid'
token[ 2]: 'User Id 0'
token[ 3]: '15'
token[ 4]: 'string'
token[ 5]: 'd'
token[ 6]: 'k'
token[ 7]: 'y'
token[ 8]: 'y'
token[ 9]: ''
token[10]: ''
token[11]: '0'
token[12]: '0'

仔細看看,如果您有其他問題,請告訴我。

我想使用fscanf將連續的標簽讀取為空字段並將它們存儲在結構中。

理想情況下,代碼應該讀取一行 ,就像fgets() ,然后解析字符串

然而繼續使用fscanf() ,這可以在一個循環中完成。


主要思想是使用"%[^/t/n]"來讀取一個標記。 如果下一個字符是'\\t' ,那么返回值將不是1.測試它。 寬度限制是明智的。

然后讀取分隔符並查找選項卡,行尾或發生文件結束/錯誤。

#define TABS_PER_LINE 12
#define TOKENS_PER_LINE (TABS_PER_LINE + 1)
#define TOKEN_SIZE 100
#define TOKEN_FMT_N "99"

int fread_tab_delimited_line(FILE *istream, int n, char token[n][TOKEN_SIZE]) {
  for (int i = 0; i < n; i++) {
    int token_count = fscanf(istream, "%" TOKEN_FMT_N "[^\t\n]", token[i]);
    if (token_count != 1) {
      token[i][0] = '\0';  // Empty token
    }
    char separator;
    int term_count = fscanf(istream, "%c", &separator);  // fgetc() makes more sense here
    // if end-of-file or end-of-line
    if (term_count != 1 || separator == '\n') {
      if (i == 0 && token_count != 1 && term_count != 1) {
        return 0;
      }
      return i + 1;
    }
    if (separator != '\t') {
      return -1;  // Token too long
    }
  }
  return -1;  // Token too many tokens found
}

樣品驅動代碼

void test_tab_delimited_line(FILE *istream) {
  char token[TOKENS_PER_LINE][TOKEN_SIZE];
  long long line_count = 0;
  int token_count;
  while ((token_count = fread_tab_delimited_line(istream, TOKENS_PER_LINE, token)) > 0) {
    printf("Line %lld\n", ++line_count);
    for (int i = 0; i < token_count; i++) {
      printf("%d: <%s>\n", i, token[i]);
    }
  } while (token_count > 0);
  if (token_count < 0) {
    puts("Trouble reading any tokens.");
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM