用C解析文本

时间:2009-09-05 21:03:48

标签: c parsing

我有一个这样的文件:

...
words 13
more words 21
even more words 4
...

(一般格式是一个非数字字符串,然后是一个空格,然后是任意数量的数字和换行符)

我想解析每一行,将单词放入结构的一个字段,将数字放入另一个字段。现在我正在使用一个难看的黑客读取线,而字符不是数字,然后阅读其余的。我相信有一个更清晰的方式。

7 个答案:

答案 0 :(得分:6)

编辑:您可以使用pNum-buf获取字符串字母部分的长度,并使用strncpy()将其复制到另一个缓冲区中。请务必在目标缓冲区的末尾添加“\ 0”。我会在pNum ++之前插入这段代码。

int len = pNum-buf;
strncpy(newBuf, buf, len-1);
newBuf[len] = '\0';

您可以将整行读入缓冲区,然后使用:

char *pNum;
if (pNum = strrchr(buf, ' ')) {
  pNum++;
}

获取指向数字字段的指针。

答案 1 :(得分:1)

fscanf(file, "%s %d", word, &value);

这将值直接转换为字符串和整数,并应对空格和数字格式等的变化。

修改

哎呀,我忘记了单词之间有空格。 在那种情况下,我会做以下事情。 (请注意,它会截断'line'中的原始文本)

// 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函数解决此问题,但由于您只搜索您感兴趣的字符,因此上述内容可能更有效。

答案 2 :(得分:0)

您可以尝试使用strtok()来标记每一行,然后检查每个标记是一个数字还是一个单词(一旦您拥有标记字符串,这是一个相当简单的检查 - 只需查看标记的第一个字符)。

答案 3 :(得分:0)

假设数字紧跟'\ n'。 你可以读取每一行到字符缓冲区,在整行使用sscanf(“%d”)来获取数字,然后计算这个数字在文本字符串末尾所占的字符数。

答案 4 :(得分:0)

根据字符串的复杂程度,您可能需要使用PCRE库。至少你可以编译一个perl'ish正则表达式来分割你的行。但这可能有点过分了。

答案 5 :(得分:0)

根据描述,这是我要做的:使用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;
}

答案 6 :(得分:0)

鉴于描述,我想我会使用这个(现已测试的)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(*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”并正确处理十六进制值。 您可能更愿意确保单词部分中没有数字;这段代码不在乎。