[英]Parsing text in C
我有一個這樣的文件:
...
words 13
more words 21
even more words 4
...
(一般格式是一串非數字,然后是空格,然后是任意數量的數字和換行符)
我想解析每一行,將單詞放入結構的一個字段,將數字放入另一個字段。 現在,我正在使用一種丑陋的技巧來閱讀該行,而字符不是數字,然后閱讀其余部分。 我相信有一個更清晰的方法。
編輯:您可以使用 pNum-buf 獲取字符串的字母部分的長度,並使用 strncpy() 將其復制到另一個緩沖區中。 請務必在目標緩沖區的末尾添加一個 '\0'。 我會在 pNum++ 之前插入這段代碼。
int len = pNum-buf;
strncpy(newBuf, buf, len-1);
newBuf[len] = '\0';
您可以將整行讀入緩沖區,然后使用:
char *pNum;
if (pNum = strrchr(buf, ' ')) {
pNum++;
}
獲取指向數字字段的指針。
fscanf(file, "%s %d", word, &value);
這將值直接轉換為字符串和整數,並處理空格和數字格式等的變化。
編輯
哎呀,我忘了你的單詞之間有空格。 在這種情況下,我會執行以下操作。 (請注意,它會截斷“行”中的原始文本)
// Scan to find the last space in the line
char *p = line;
char *lastSpace = null;
while(*p != '\0')
{
if (*p == ' ')
lastSpace = p;
p++;
}
if (lastSpace == null)
return("parse error");
// Replace the last space in the line with a NUL
*lastSpace = '\0';
// Advance past the NUL to the first character of the number field
lastSpace++;
char *word = text;
int number = atoi(lastSpace);
您可以使用 stdlib 函數解決此問題,但上述方法可能更有效,因為您只搜索您感興趣的字符。
鑒於描述,我想我會使用這個(現已測試)C99代碼的變體:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
struct word_number
{
char word[128];
long number;
};
int read_word_number(FILE *fp, struct word_number *wnp)
{
char buffer[140];
if (fgets(buffer, sizeof(buffer), fp) == 0)
return EOF;
size_t len = strlen(buffer);
if (buffer[len-1] != '\n') // Error if line too long to fit
return EOF;
buffer[--len] = '\0';
char *num = &buffer[len-1];
while (num > buffer && !isspace((unsigned char)*num))
num--;
if (num == buffer) // No space in input data
return EOF;
char *end;
wnp->number = strtol(num+1, &end, 0);
if (*end != '\0') // Invalid number as last word on line
return EOF;
*num = '\0';
if (num - buffer >= sizeof(wnp->word)) // Non-number part too long
return EOF;
memcpy(wnp->word, buffer, num - buffer);
return(0);
}
int main(void)
{
struct word_number wn;
while (read_word_number(stdin, &wn) != EOF)
printf("Word <<%s>> Number %ld\n", wn.word, wn.number);
return(0);
}
您可以通過為不同的問題返回不同的值來改進錯誤報告。 您可以使其與行的單詞部分的動態分配內存一起使用。 你可以讓它使用比我允許的更長的行。 您可以向后掃描數字而不是非空格 - 但這允許用戶編寫“abc 0x123”並且正確處理十六進制值。 您可能更願意確保單詞部分沒有數字; 這段代碼不在乎。
您可以嘗試使用strtok()對每一行進行標記,然后檢查每個標記是數字還是單詞(一旦有了標記字符串,就可以進行相當簡單的檢查 - 只需查看標記的第一個字符)。
假設數字后面緊跟着'\n'。 您可以將每一行讀取到字符緩沖區,在整行上使用 sscanf("%d") 來獲取數字,然后計算該數字在文本字符串末尾所占用的字符數。
根據您的字符串變得多么復雜,您可能需要使用 PCRE 庫。 至少這樣你就可以編譯一個 perl'ish 正則表達式來分割你的行。 不過,這可能有點矯枉過正。
鑒於描述,這就是我要做的:使用 fgets() 將每一行作為單個字符串讀取(確保目標緩沖區足夠大),然后使用 strtok() 拆分行。 要確定每個標記是單詞還是數字,我會使用 strtol() 來嘗試轉換並檢查錯誤情況。 例子:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/**
* Read the next line from the file, splitting the tokens into
* multiple strings and a single integer. Assumes input lines
* never exceed MAX_LINE_LENGTH and each individual string never
* exceeds MAX_STR_SIZE. Otherwise things get a little more
* interesting. Also assumes that the integer is the last
* thing on each line.
*/
int getNextLine(FILE *in, char (*strs)[MAX_STR_SIZE], int *numStrings, int *value)
{
char buffer[MAX_LINE_LENGTH];
int rval = 1;
if (fgets(buffer, buffer, sizeof buffer))
{
char *token = strtok(buffer, " ");
*numStrings = 0;
while (token)
{
char *chk;
*value = (int) strtol(token, &chk, 10);
if (*chk != 0 && *chk != '\n')
{
strcpy(strs[(*numStrings)++], token);
}
token = strtok(NULL, " ");
}
}
else
{
/**
* fgets() hit either EOF or error; either way return 0
*/
rval = 0;
}
return rval;
}
/**
* sample main
*/
int main(void)
{
FILE *input;
char strings[MAX_NUM_STRINGS][MAX_STRING_LENGTH];
int numStrings;
int value;
input = fopen("datafile.txt", "r");
if (input)
{
while (getNextLine(input, &strings, &numStrings, &value))
{
/**
* Do something with strings and value here
*/
}
fclose(input);
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.