Парсинг текста в C

Когда в сомнении, бомбите приложение!

Проверка каждый параметр в начале каждый метод (не имеет ли explictly кодирование его самостоятельно или использование основанного на контракте программирования значения здесь) и бомбят за корректным исключением и/или значимым сообщением об ошибке, если любое предварительное условие к коду не встречено.

Все мы знаем об этих неявных предварительных условиях , когда мы пишем код , но если они явно не проверяются на, мы создаем лабиринты для нас, когда что-то идет не так, как надо позже, и стопки десятков вызовов метода разделяют происшествие признака и фактического местоположения, где предварительное условие не встречено (=where, проблема/ошибка на самом деле).

6
задан Chris Lutz 5 September 2009 в 21:50
поделиться

7 ответов

Изменить: вы можете использовать pNum-buf, чтобы получить длину алфавитной части строки, и использовать strncpy (), чтобы скопировать ее в другой буфер. Не забудьте добавить '\ 0' в конец целевого буфера. Я бы вставил этот код перед pNum ++.

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

Вы можете прочитать всю строку в буфер и затем использовать:

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

, чтобы получить указатель на числовое поле.

6
ответ дан 11 December 2019 в 00:40
поделиться
fscanf(file, "%s %d", word, &value);

Это переводит значения непосредственно в строку и целое число, и справляется с вариациями в пробельных и числовых форматах и ​​т. Д.

Edit

Ой, я забыл, что у вас были пробелы между слова. В таком случае я бы сделал следующее. (Обратите внимание, что он обрезает исходный текст в строке)

// 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, но описанный выше вариант, вероятно, будет более эффективным, поскольку вы ищете только те символы, которые вас интересуют.

1
ответ дан 11 December 2019 в 00:40
поделиться

Вы можете попробовать использовать strtok () для токенизации каждой строки, а затем проверьте, является ли каждый токен числом или словом (довольно тривиальная проверка, когда у вас есть строка токена - просто посмотрите на первый символ токена).

0
ответ дан 11 December 2019 в 00:40
поделиться

Предполагается, что сразу за номером следует '\ n'. вы можете прочитать каждую строку в буфере символов, использовать sscanf ("% d") для всей строки, чтобы получить число, а затем вычислить количество символов, которое это число занимает в конце текстовой строки.

0
ответ дан 11 December 2019 в 00:40
поделиться

В зависимости от того, насколько сложными становятся ваши строки, вы можете использовать библиотеку PCRE. По крайней мере, таким образом вы можете скомпилировать Perl'ish регулярное выражение для разделения ваших строк. Хотя это может быть излишним.

0
ответ дан 11 December 2019 в 00:40
поделиться

Учитывая описание, я думаю, что я бы использовал вариант этого (теперь протестированного) кода 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», и шестнадцатеричное значение обрабатывается правильно. Вы можете предпочесть убедиться, что в части слова нет цифр; этому коду все равно.

0
ответ дан 11 December 2019 в 00:40
поделиться

Учитывая описание, вот что я бы сделал: прочитал каждую строку как одну строку с помощью 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;
}
0
ответ дан 11 December 2019 в 00:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: