用C语言分析文本

用C语言分析文本,c,parsing,C,Parsing,我有这样一个文件: ... words 13 more words 21 even more words 4 ... (一般格式为非数字字符串、空格、任意位数和换行) 我想解析每一行,把单词放在结构的一个字段中,把数字放在另一个字段中。现在我正在用一种难看的技巧,在字符不是数字的时候读这行,然后读其余的。我相信有一种更清晰的方法。您可以尝试使用标记化每一行,然后检查每个标记是数字还是单词(一旦您有了标记字符串,这是一个相当简单的检查-只需查看标记的第一个字符即可)。编辑:您可以使用pNum b

我有这样一个文件:

...
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++;
}

获取指向数字字段的指针

假设数字后面紧跟着“\n”。 您可以将每一行读取到chars buffer,在整行上使用sscanf(“%d”)来获取数字,然后计算该数字在文本字符串结尾处的字符数

fscanf(file, "%s %d", word, &value);
这将直接将值转换为字符串和整数,并处理空格和数字格式等的变化

编辑

哎呀,我忘了你的字里行间有空格。 在这种情况下,我会做以下事情。(请注意,它会截断“行”中的原始文本)


您可以使用stdlib函数来解决这个问题,但上述方法可能更有效,因为您只搜索您感兴趣的字符。

根据字符串的复杂程度,您可能需要使用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;
}
#包括
#包括
#包括
/**
*从文件中读取下一行,将令牌拆分为
*多个字符串和一个整数。假定输入行
*不得超过最大线长度,且每个单独的字符串不得超过最大线长度
*超过最大长度。否则情况会变得更糟
*有趣。还假定整数是最后一个
*每行上都有一个东西。
*/
int getNextLine(文件*in,字符(*strs)[MAX_STR_SIZE],int*numStrings,int*value)
{
字符缓冲区[最大行长度];
int-rval=1;
if(fgets(缓冲区、缓冲区、缓冲区大小))
{
char*token=strtok(缓冲区“”);
*numStrings=0;
while(令牌)
{
char*chk;
*值=(int)strtol(令牌和chk,10);
如果(*chk!=0&&*chk!='\n')
{
strcpy(strs[(*numStrings)++],令牌);
}
令牌=strtok(空,“”);
}
}
其他的
{
/** 
*fgets()命中EOF或error;任一方向返回0
*/
rval=0;
}
返回rval;
}
/**
*样品总管
*/
内部主(空)
{
文件*输入;
字符字符串[MAX_NUM_strings][MAX_STRING_LENGTH];
整数字符串;
int值;
输入=fopen(“datafile.txt”,“r”);
如果(输入)
{
while(getNextLine(输入、字符串、numStrings和值))
{
/**
*在这里使用字符串和值进行操作
*/
}
fclose(输入);
}
返回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);
}
#包括
#包括
#包括
#包括
结构字号
{
字符字[128];
长数;
};
整型读取字编号(文件*fp,结构字编号*wnp)
{
字符缓冲区[140];
如果(fgets(缓冲区,sizeof(缓冲区),fp)==0)
返回EOF;
大小长度=strlen(缓冲区);
if(buffer[len-1]!='\n')//如果行太长而无法容纳,则出错
返回EOF;
缓冲区[--len]='\0';
char*num=&buffer[len-1];
while(num>buffer&&!isspace(*num))
num--;
if(num==buffer)//输入数据中没有空格
返回EOF;
字符*结束;
wnp->number=strtol(num+1,&end,0);
if(*end!='\0')//作为第行最后一个字的数字无效
返回EOF;
*num='\0';
如果(num-buffer>=sizeof(wnp->word))//非数字部分太长
返回EOF;
memcpy(wnp->word,buffer,num-buffer);
返回(0);
}
内部主(空)
{
结构字编号wn;
while(读取单词和数字(标准输入和数值)!=EOF)
printf(“字号%ld\n”,wn.Word,wn.Number);
返回(0);
}
您可以通过为不同的问题返回不同的值来改进错误报告。 您可以使用为行的字部分动态分配的内存使其工作。 你可以用比我允许的更长的线。 您可以向后扫描数字而不是非空格,但这允许用户写入“abc 0x123”,并且十六进制值处理正确。
您可能更愿意确保单词部分中没有数字;此代码不重要。

请更具体地说明格式。单词和数字之间的分隔符是否总是一个空格(即不是两个空格,或者空格和制表符)?数字后面(换行符之前)可以有空格吗?单词可以包含数字吗?这就是我写的,多亏了Stack Overflow的橙色ajaxy警报:-)嘿,我通常也在警报的另一边。这很有效,但字母部分呢?如何将其复制到最后一个空格?仅查看令牌的第一个字符并不是一个非常可靠的检查。我不会那么信任文件中的数据。这取决于文件的来源。如果这些文件是由应用程序生成的内部文件(或格式严格且已知的预先存在的文件),则r
#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);
}