Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Программирование Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 [2]      все
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
kealon(Ruslan),

да. это самое плохое место. не знаю пока как победить. есть коечно одно решение которое придумали до меня - обрамлять тэги кавычками <SOI>, <EOI>, <SOT>, <EOT> или <I>, <I/>, <T>, <T/>.
но это решение не такое генерик как хотелось бы.
11 янв 17, 14:20    [20093794]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
Dima T,

спасибо. попробую доработать. почему то парсит один блок и выходит.
11 янв 17, 15:04    [20094073]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Dima T
Member

Откуда:
Сообщений: 9902
jenya7
Dima T,

спасибо. попробую доработать. почему то парсит один блок и выходит.

Ты мой код запускал? Там должно быть так
* Ne*
* Fo*
т.к. буфер 4 байта и строка с ошибками (красным выделил)
"SOI Happy SOT New EOT SOT Year EOI SOI Folks EOI"

Если на какой-то другой строке неправильно работает - давай строку, поправлю.
11 янв 17, 15:16    [20094109]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
Dima T,
моя ошибка. все класно работает. Dima T как всегда крут. :)
11 янв 17, 15:18    [20094120]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Dima T
Member

Откуда:
Сообщений: 9902
Пользуйся.

Еще думаю неправильно возвращать часть строки если она целиком в буфер не поместилась, наверно лучше пустую возвращать
			} else if(s > 1) { // есть место в буфере
...
			} else { // буфер маловат
				*buf = 0;
			}

Сам подумай как правильнее ошибки обрабатывать, что где проверяется я подписал.
11 янв 17, 15:51    [20094291]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 1315
Dima T
Еще думаю неправильно возвращать часть строки если она целиком в буфер не поместилась, наверно лучше пустую возвращать

лучше не копировать, а возвращать начало текста и длину, проще будет
11 янв 17, 16:05    [20094391]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Пётр Седов
Member

Откуда: Санкт-Петербург
Сообщений: 628
jenya7
у меня голый С.
Ну вот, а здесь приличный форум.

jenya7
ничего не понимаю. что происходит.
Это нормально, вы же задали вопрос на sql.ru.

jenya7
задача на несколько строк кода.
Только если писать на ультракоротком языке. На C побольше выйдет.

Кстати, форум «C++» -- он и для вопросов по C тоже.

Dima T
	char buf[4];
Так вы, Dim, любите буферы фиксированой длины?

kealon(Ruslan)
лучше не копировать, а возвращать начало текста и длину, проще будет
А я бы вообще ничего не возвращал, а просто вызывал бы функции обработки блоков:
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

/* только для строковых литералов */
#define SL_LEN(string_lit) (sizeof(string_lit) - 1)

#define INSTRUCTION_START "SOI"
#define INSTRUCTION_END "EOI"
#define TEST_START "SOT"
#define TEST_END "EOT"

bool handle_instruction_block(const char block[], size_t block_len);
bool handle_test_block(const char block[], size_t block_len);

bool parse_blocks(const char text[]) {
  size_t pos, block_start, block_end;
  const char* end_marker;

  pos = 0;
  for (;;) {
    while (text[pos] == ' ') pos++; /* пропускаем пробелы */

    if (text[pos] == '\0')
      break;

    if (strncmp(text + pos, INSTRUCTION_START, SL_LEN(INSTRUCTION_START)) == 0) {
      pos += SL_LEN(INSTRUCTION_START);
      while (text[pos] == ' ') pos++;
      block_start = pos;
      end_marker = strstr(text + pos, INSTRUCTION_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      if (block_start < pos) {
        block_end = pos;
        while (text[block_end - 1] == ' ') block_end--;
        if (!handle_instruction_block(text + block_start, block_end - block_start)) return false;
      } else {
        if (!handle_instruction_block(NULL, 0)) return false;
      }
      pos += SL_LEN(INSTRUCTION_END);
    } else if (strncmp(text + pos, TEST_START, SL_LEN(TEST_START)) == 0) {
      pos += SL_LEN(TEST_START);
      while (text[pos] == ' ') pos++;
      block_start = pos;
      end_marker = strstr(text + pos, TEST_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      if (block_start < pos) {
        block_end = pos;
        while (text[block_end - 1] == ' ') block_end--;
        if (!handle_test_block(text + block_start, block_end - block_start)) return false;
      } else {
        if (!handle_test_block(NULL, 0)) return false;
      }
      pos += SL_LEN(TEST_END);
    } else {
      return false;
    }
  }

  return true;
}

bool handle_instruction_block(const char block[], size_t block_len) {
  if (block != NULL) {
    /* строка block не завершается нулевым char-ом ('\0'), поэтому явно указываем длину */
    printf("instruction '%.*s'\n", (int)block_len, block);
  } else {
    printf("empty instruction\n");
  }
  return true;
}

bool handle_test_block(const char block[], size_t block_len) {
  if (block != NULL) {
    printf("test '%.*s'\n", (int)block_len, block);
  } else {
    printf("empty test\n");
  }
  return true;
}

int main() {
  parse_blocks(" SOI Happy EOI  SOT New EOT  SOT Year EOT  SOT EOT  SOI Folks EOI ");
  return 0;
}
Вывод на консоль:
instruction 'Happy'
test 'New'
test 'Year'
empty test
instruction 'Folks'
12 янв 17, 05:02    [20096498]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

Откуда: @
Сообщений: 26468
Пётр Седов
Так вы, Dim, любите буферы фиксированой длины?

в контроллерах всегда овердохера динамической памяти?
12 янв 17, 13:12    [20098123]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
Пётр Седов,
у Dima T код раза в 3 меньше.
12 янв 17, 17:31    [20099521]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 32015
jenya7
OoCc
или использовать готовый регэкс автомат типа такого

у меня голый С.


lib pcre
12 янв 17, 19:46    [20100056]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Пётр Седов
Member

Откуда: Санкт-Петербург
Сообщений: 628
Изопропил
Пётр Седов
Так вы, Dim, любите буферы фиксированой длины?

в контроллерах всегда овердохера динамической памяти?
В этой задаче не нужно динамическое распределение памяти, в моём коде его и нет. Кстати, автор вопроса не писал, что задача для controller-а.

jenya7
Пётр Седов,
у Dima T код раза в 3 меньше.
Это Perl-овская краткость, когда кода мало, но надо мозг сломать, чтобы понять, что тут происходит. Кстати, Perl уже почти никому не нужен, и это неслучайно. По коду Dima T:

* Плохо-читабельный write-only код. Сбивающие с толку приёмы, например указатель p смещается как в заголовке цикла, так и в его теле:
Dima T
	const char* p = ...;
	for(;*p != 0; p++) {
		...
			p += 2;
		...
	}

* Использование буфера фиксированной длины. Приемлемо разве что в учебных заданиях, во «взрослом» коде -- почти никогда. Кроме случаев, когда есть гарантированное ограничение на длину строки (например, WinAPI-шная константа MAX_PATH, которая используется в структуре WIN32_FIND_DATA). Но вы такое гарантированное ограничение не упоминаете.

* Код, который обрабатывает блоки, не знает тип блока:
Dima T
int main (void) {
	//const char* p = "SOI Happy EOISOT New EOT SOT Year EOT SOI Folks EOI ";
	const char* p = "SOI Happy SOT New EOT SOT Year EOI SOI Folks EOI ";
	char buf[4];
	while(p = parse(p, buf, 4)) {
		printf("*%s*\n", buf);
	}
	return 0;
}
Надо ещё выводить на консоль тип блока -- instruction или test.

* Не удаляются пробелы до и после блоков (" New ", " Folks " -- с пробелами). Хотя, если вам это и не надо, то мой код можно упростить:
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

/* только для строковых литералов */
#define SL_LEN(string_lit) (sizeof(string_lit) - 1)

#define INSTRUCTION_START "SOI"
#define INSTRUCTION_END "EOI"
#define TEST_START "SOT"
#define TEST_END "EOT"

bool handle_instruction_block(const char block[], size_t block_len);
bool handle_test_block(const char block[], size_t block_len);

bool parse_blocks(const char text[]) {
  size_t pos, block_start;
  const char* end_marker;

  pos = 0;
  for (;;) {
    while (text[pos] == ' ') pos++; /* пропускаем пробелы */

    if (text[pos] == '\0')
      break;

    if (strncmp(text + pos, INSTRUCTION_START, SL_LEN(INSTRUCTION_START)) == 0) {
      pos += SL_LEN(INSTRUCTION_START);
      block_start = pos;
      end_marker = strstr(text + pos, INSTRUCTION_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      if (!handle_instruction_block(text + block_start, pos - block_start)) return false;
      pos += SL_LEN(INSTRUCTION_END);
    } else if (strncmp(text + pos, TEST_START, SL_LEN(TEST_START)) == 0) {
      pos += SL_LEN(TEST_START);
      block_start = pos;
      end_marker = strstr(text + pos, TEST_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      if (!handle_test_block(text + block_start, pos - block_start)) return false;
      pos += SL_LEN(TEST_END);
    } else {
      return false;
    }
  }

  return true;
}

bool handle_instruction_block(const char block[], size_t block_len) {
  /* строка block не завершается нулевым char-ом ('\0'), поэтому явно указываем длину */
  printf("instruction '%.*s'\n", (int)block_len, block);
  return true;
}

bool handle_test_block(const char block[], size_t block_len) {
  printf("test '%.*s'\n", (int)block_len, block);
  return true;
}

int main() {
  parse_blocks(" SOI Happy EOI  SOT New EOT  SOT Year EOT  SOT EOT  SOI Folks EOI ");
  return 0;
}
Вывод на консоль:
instruction ' Happy '
test ' New '
test ' Year '
test ' '
instruction ' Folks '
13 янв 17, 03:11    [20100847]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

Откуда: @
Сообщений: 26468
Пётр Седов
Кстати, автор вопроса не писал, что задача для controller-а.

это не тайна, есть предыдущие вопросы и ответы
13 янв 17, 21:08    [20104447]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
Пётр Седов
* Использование буфера фиксированной длины. Приемлемо разве что в учебных заданиях, во «взрослом» коде -- почти никогда. Кроме случаев, когда есть гарантированное ограничение на длину строки (например, WinAPI-шная константа MAX_PATH, которая используется в структуре WIN32_FIND_DATA). Но вы такое гарантированное ограничение не упоминаете.


тут в чем проблема. я пишу под эмбедед. если не использоать буфер фиксированной длины то нужна динамическая алокация памяти. а в эмбедед это плохо.
15 янв 17, 15:18    [20107563]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Пётр Седов
Member

Откуда: Санкт-Петербург
Сообщений: 628
jenya7, если вам надо блоки иметь как ноль-завершаемые строки, и можно менять содержимое исходной строки, то можно поступить так, как делает функция strtok: писать завершающие нулевые char-ы ('\0') прямо в исходную строку:
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

/* только для строковых литералов */
#define SL_LEN(string_lit) (sizeof(string_lit) - 1)

#define INSTRUCTION_START "SOI"
#define INSTRUCTION_END "EOI"
#define TEST_START "SOT"
#define TEST_END "EOT"

bool handle_instruction_block(char block[]);
bool handle_test_block(char block[]);

/* меняет содержимое строки text */
bool parse_blocks(char text[]) {
  size_t pos, block_start;
  char* end_marker;

  pos = 0;
  for (;;) {
    /* пропускаем пробелы */
    while ((text[pos] == ' ') || (text[pos] == '\t') || (text[pos] == '\r') || (text[pos] == '\n'))
      pos++;

    if (text[pos] == '\0')
      break;

    if (strncmp(text + pos, INSTRUCTION_START, SL_LEN(INSTRUCTION_START)) == 0) {
      pos += SL_LEN(INSTRUCTION_START);
      block_start = pos;
      end_marker = strstr(text + pos, INSTRUCTION_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      text[pos] = '\0'; /* обрубаем строку в том месте, где находится INSTRUCTION_END */
      if (!handle_instruction_block(text + block_start)) return false;
      pos += SL_LEN(INSTRUCTION_END);
    } else if (strncmp(text + pos, TEST_START, SL_LEN(TEST_START)) == 0) {
      pos += SL_LEN(TEST_START);
      block_start = pos;
      end_marker = strstr(text + pos, TEST_END);
      if (end_marker == NULL) return false;
      pos = end_marker - text;
      text[pos] = '\0'; /* обрубаем строку в том месте, где находится TEST_END */
      if (!handle_test_block(text + block_start)) return false;
      pos += SL_LEN(TEST_END);
    } else {
      return false;
    }
  }

  return true;
}

/* может менять содержимое строки block */
bool handle_instruction_block(char block[]) {
  printf("instruction '%s'\n", block);
  return true;
}

/* может менять содержимое строки block */
bool handle_test_block(char block[]) {
  printf("test '%s'\n", block);
  return true;
}

int main() {
  char text[] = " SOI Happy EOI  SOT New EOT  SOT Year EOT  SOT EOT  SOI Folks EOI ";
  parse_blocks(text);
  return 0;
}
Вывод на консоль:
instruction ' Happy '
test ' New '
test ' Year '
test ' '
instruction ' Folks '
вчера, 05:20    [20108867]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 679
Пётр Седов,
понял. спасибо.
вчера, 09:37    [20109073]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 [2]      все
Все форумы / Программирование Ответить