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

Откуда:
Сообщений: 711
Мне нужно выделить из текста блоки разного типа. У каждого типа есть начальный маркер и конечный маркер. Сейчас есть два типа текстовых блоков - инструкция и тест. Соответственно маркеры выглядят так:
автор
SOI – start of instruction
EOI – end of instruction
SOT – start of test
EOT – end of test

И текст выглядит так:
автор
SOI
Line1
Line2
Line3
EOI
SOT
Line4
Line5
Line6
EOT

Мой топорный вариант выглядит так.
uint32_t Parse(char *text, char *buf, uint32_t *text_type, uint32_t *idx)
{
    uint32_t loc_idx = *idx;
    uint32_t txt_len = strlen(text);
    uint32_t start_pos = 0;
    uint32_t end_pos = 0;
    uint32_t start_found = 0;
    char *pchr;
    
    if (loc_idx >= txt_len) return PARSE_FAIL;
    
    //find SOI - start of instraction
    pchr = strstr(&text[loc_idx], START_OF_INSTRACTION);
    //if(pchr == NULL) return PARSE_FAIL;
    if (pchr != NULL)
    {
        start_pos = pchr - text + strlen(START_OF_INSTRACTION);
        start_found = 1;
    }
        
    //find EOI - end of instraction
    pchr = strstr(text, END_OF_INSTRACTION);
    //if(pchr == NULL) return PARSE_FAIL;  
    if (start_found && pchr != NULL)
    {
        end_pos = pchr - text;
        //copy the found block
        memcpy(buf, &text[start_pos], (end_pos - start_pos));
        buf[(end_pos - start_pos)] = '\0';
        *text_type = TXT_TYPE_INSTRACTION;
        *idx = end_pos + strlen(END_OF_INSTRACTION);
        return PARSE_SUCCESS;
    }
    
    //find SOT - start of test
    pchr = strstr(&text[loc_idx], START_OF_TEST);
    if (pchr != NULL)
    {
        start_pos = pchr - text + strlen(START_OF_TEST);
        start_found = 1;
    }
    
    //find EOT - end of test
    pchr = strstr(text, END_OF_TEST);
    if (start_found && pchr != NULL)
    {
        end_pos = pchr - text;
        //copy the found block
        memcpy(buf, &text[start_pos], (end_pos - start_pos)); 
        buf[(end_pos - start_pos)] = '\0';
        *text_type = TXT_TYPE_TEST;
        *idx = end_pos + strlen(END_OF_TEST);
        return PARSE_SUCCESS;
    }
       
    return PARSE_FAIL; 

И он работает если в тексте есть два блока.
Но если текст выглядит скажем так
автор
SOI
line1
line2
line3
EOI
SOT
line4
line5
line6
EOT
SOT
line7
line8
line9
EOT
SOI
line10
line11
line12
EOI


То весь мой парсер ломается. Как можно улучшить алгоритм?
11 янв 17, 09:35    [20092329]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Akina
Member

Откуда: Зеленоград, Москва, Россия
Сообщений: 15604
Сформулируйте все условия, а не основные.

1) Что значит "выделить"? что хотите получить в итоге и в каком виде?
2) Есть ли гарантия, что любой текст, не являющийся маркером, находится в блоке? или бывает текст вне блоков (в т.ч. "пустые" строки)?
3) Есть ли гарантия согласованности разметки? или возможны пересечения блоков, незакрытые блоки и пр?
11 янв 17, 10:12    [20092415]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

Откуда:
Сообщений: 29514
jenya7
То весь мой парсер ломается. Как можно улучшить алгоритм?

1)расписать синтаксис в форме Бэкуса — Наура (BNF)
2)запрограммировать автомат (если неограниченной вложенности нет - то конечный)

нужно последовательно обрабатывать каждый символ(максимум заглядывая на один вперёд, но в этой задаче не придётся) и изменять состояние , а не пытаться сканировать строку вперёд
11 янв 17, 10:34    [20092473]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 711
Akina
Сформулируйте все условия, а не основные.

1) Что значит "выделить"? что хотите получить в итоге и в каком виде?
2) Есть ли гарантия, что любой текст, не являющийся маркером, находится в блоке? или бывает текст вне блоков (в т.ч. "пустые" строки)?
3) Есть ли гарантия согласованности разметки? или возможны пересечения блоков, незакрытые блоки и пр?


Нужно скопировать текст в буфер между маркерами SOI-EOI , SOT-EOT.
скажем в HTML документе тоже есть блоки – header, paragraph, div.
11 янв 17, 10:50    [20092526]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
OoCc
Member

Откуда: с Кавказа
Сообщений: 1299
или использовать готовый регэкс автомат типа такого
11 янв 17, 10:53    [20092538]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

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

у меня голый С.
11 янв 17, 11:14    [20092641]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Akina
Member

Откуда: Зеленоград, Москва, Россия
Сообщений: 15604
jenya7, пожалуйста, отвечайте на те вопросы, которые Вам задают, а не на вопросы, которые Вы себе сами придумали.

jenya7
Нужно скопировать текст в буфер между маркерами SOI-EOI , SOT-EOT.

И что же должно быть помещено в буфер для показанного Вами текста?

jenya7
скажем в HTML документе тоже есть блоки – header, paragraph, div

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

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

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

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

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

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

в этом нет проблем, большинство парсер-генераторов поддерживают С да и нагенерированный автомат выполняется элементарно
11 янв 17, 11:26    [20092721]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

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

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

Откуда: Нижневартовск
Сообщений: 1882
Изопропил,

не скажи, как раз таки эту задачу можно решить за один побайтный проход если иметь свой лексер-генератор и знать как он работает
11 янв 17, 11:56    [20092917]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 711
ничего не понимаю. что происходит.
есть строка "SOI Happy EOI SOT New EOT SOT Year EOT SOI Folks EOI ".
блоки приходят в любом порядке. могут быть только SOI-EOI, SOI-EOI…. Или SOT-EOT, SOT-EOT….. или вперемежку SOI-EOI, SOT-EOT, SOI-EOI, SOT-EOT .
в результате нужно получить buf1 = Happy, buf2 = New, buf3 = Year, buf4 = Folks.
можно даже не одновременно а по очереди.
какие регексы, какие библиотеки. задача на несколько строк кода.
11 янв 17, 11:58    [20092933]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

Откуда:
Сообщений: 29514
kealon(Ruslan)
Изопропил,

не скажи, как раз таки эту задачу можно решить за один побайтный проход если иметь свой лексер-генератор и знать как он работает

можно решить естественно за один проход и без генератора )
11 янв 17, 12:04    [20092969]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Изопропил
Member

Откуда:
Сообщений: 29514
jenya7
задача на несколько строк кода.

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

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

Откуда: Нижневартовск
Сообщений: 1882
jenya7
ничего не понимаю. что происходит.
есть строка "SOI Happy EOI SOT New EOT SOT Year EOT SOI Folks EOI ".
блоки приходят в любом порядке. могут быть только SOI-EOI, SOI-EOI…. Или SOT-EOT, SOT-EOT….. или вперемежку SOI-EOI, SOT-EOT, SOI-EOI, SOT-EOT .
в результате нужно получить buf1 = Happy, buf2 = New, buf3 = Year, buf4 = Folks.
можно даже не одновременно а по очереди.
какие регексы, какие библиотеки. задача на несколько строк кода.

ну если тебе нужно один раз найти, то никаких проблем
    //find SOI - start of instraction
    pchr1 = strstr(&text[loc_idx], START_OF_INSTRACTION);
   //find SOT - start of test
    pchr2 = strstr(&text[loc_idx], START_OF_TEST);

смотришь какой раньше и ищешь его завершение, очень топорно, но работать будет

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

Откуда: Нижневартовск
Сообщений: 1882
Изопропил
можно решить естественно за один проход и без генератора )

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

Откуда:
Сообщений: 711
Изопропил,

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

Откуда:
Сообщений: 711
kealon(Ruslan)
jenya7
ничего не понимаю. что происходит.
есть строка "SOI Happy EOI SOT New EOT SOT Year EOT SOI Folks EOI ".
блоки приходят в любом порядке. могут быть только SOI-EOI, SOI-EOI…. Или SOT-EOT, SOT-EOT….. или вперемежку SOI-EOI, SOT-EOT, SOI-EOI, SOT-EOT .
в результате нужно получить buf1 = Happy, buf2 = New, buf3 = Year, buf4 = Folks.
можно даже не одновременно а по очереди.
какие регексы, какие библиотеки. задача на несколько строк кода.

ну если тебе нужно один раз найти, то никаких проблем
    //find SOI - start of instraction
    pchr1 = strstr(&text[loc_idx], START_OF_INSTRACTION);
   //find SOT - start of test
    pchr2 = strstr(&text[loc_idx], START_OF_TEST);

смотришь какой раньше и ищешь его завершение, очень топорно, но работать будет

а вот если требуется какое-то решение, которое обслуживает протокол приближенный к реальному времени, то извольте учить конечные автоматы


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

Откуда: Нижневартовск
Сообщений: 1882
jenya7
я думал об этом. как то не очень элегантно.
лесенка из побайтных switch как видимо прелагает Изопропил

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

Откуда:
Сообщений: 29514
jenya7
ну в этом то и загвоздка. мы нашли начало, нашли конец

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

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

Откуда:
Сообщений: 711
так работает.
uint32_t Parse(char *text, char *buf, uint32_t *text_type, uint32_t *idx)
{
    uint32_t loc_idx = *idx;
    uint32_t txt_len = strlen(text);
    uint32_t start_pos = 0;
    uint32_t end_pos = 0;
    uint32_t start_found = 0;
    char *pchr_i, *pchr_t;
    
    if (loc_idx >= txt_len) return PARSE_FAIL;
    
    
    //find SOI - start of instraction
    pchr_i = strstr(&text[loc_idx], START_OF_INSTRACTION);
    //find SOT - start of test
    pchr_t = strstr(&text[loc_idx], START_OF_TEST);
    
    if ((pchr_i != NULL) && (pchr_t != NULL))
    {
        start_found = 1;
        
        //marker SOI found first
        if (pchr_i < pchr_t)
        {
            start_pos = pchr_i - text + strlen(START_OF_INSTRACTION);
            //find EOI - end of instraction
            pchr_i = strstr(&text[loc_idx], END_OF_INSTRACTION);
            if (start_found && pchr_i != NULL)
            {
                end_pos = pchr_i - text;
                //copy the found block
                memcpy(buf, &text[start_pos], (end_pos - start_pos));
                buf[(end_pos - start_pos)] = '\0';
                *text_type = TXT_TYPE_INSTRACTION;
                *idx = end_pos + strlen(END_OF_INSTRACTION);
                return PARSE_SUCCESS;
            }
        }
        else  //marker SOT found first
        {
            start_pos = pchr_t - text + strlen(START_OF_TEST);
            //find EOT - end of test
            pchr_t = strstr(&text[loc_idx], END_OF_TEST);
            if (start_found && pchr_t != NULL)
            {
                end_pos = pchr_t - text;
                //copy the found block
                memcpy(buf, &text[start_pos], (end_pos - start_pos)); 
                buf[(end_pos - start_pos)] = '\0';
                *text_type = TXT_TYPE_TEST;
                *idx = end_pos + strlen(END_OF_TEST);
                return PARSE_SUCCESS;
            }
        }
    }
    else
    {
        if (pchr_i != NULL)
        {
            start_found = 1;
          
            start_pos = pchr_i - text + strlen(START_OF_INSTRACTION);
            pchr_i = strstr(&text[loc_idx], END_OF_INSTRACTION);
            if (start_found && pchr_i != NULL)
            {
                end_pos = pchr_i - text;
                //copy the found block
                memcpy(buf, &text[start_pos], (end_pos - start_pos));
                buf[(end_pos - start_pos)] = '\0';
                *text_type = TXT_TYPE_INSTRACTION;
                *idx = end_pos + strlen(END_OF_INSTRACTION);
                return PARSE_SUCCESS;
            }
            
        }
        if (pchr_t != NULL)
        {
            start_found = 1;
            
            start_pos = pchr_t - text + strlen(START_OF_TEST);
            pchr_t = strstr(&text[loc_idx], END_OF_TEST);
            if (start_found && pchr_t != NULL)
            {
                end_pos = pchr_t - text;
                //copy the found block
                memcpy(buf, &text[start_pos], (end_pos - start_pos)); 
                buf[(end_pos - start_pos)] = '\0';
                *text_type = TXT_TYPE_TEST;
                *idx = end_pos + strlen(END_OF_TEST);
                return PARSE_SUCCESS;
            }
        }
        
    }
    
    return PARSE_FAIL; 
}

можно заинлайнить повторяющийся код. сейчас попробую сделать на state machine.
11 янв 17, 13:33    [20093513]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

Откуда:
Сообщений: 711
так на state machine.
uint32_t TASKER_Parse(char *text, char *buf, uint32_t *text_type, uint32_t *idx)
{
    uint32_t loc_idx = *idx;
    uint32_t txt_len = strlen(text);
    uint32_t start_pos = 0;
    uint32_t end_pos = 0;
    uint32_t start_found = 0;
    //char buf[128];
    char *pchr_i, *pchr_t;
    
    uint32_t state = IDLE;
    
    if (loc_idx >= txt_len) return PARSE_FAIL;
    
    while (state != ST_END)
    {
        switch (state)
        {
            case IDLE:
                //find SOI - start of instraction
                pchr_i = strstr(&text[loc_idx], START_OF_INSTRACTION);
                //find SOT - start of test
                pchr_t = strstr(&text[loc_idx], START_OF_TEST);
            
                if ((pchr_i != NULL) && (pchr_t != NULL))
                {
                    start_found = 1;
                    state = ST_BOUTH_FOUND;
                }
                else
                {
                    if (pchr_i != NULL)
                    {
                        start_found = 1;
                        state = ST_SOI_FOUND;
                    }
                    else if (pchr_t != NULL)
                    {
                        start_found = 1;
                        state = ST_SOT_FOUND;
                    }
                    else
                      state = ST_END;
                }
            break;
            case ST_BOUTH_FOUND:
                //marker SOI found first
                if (pchr_i < pchr_t)
                    state = ST_SOI_FOUND;
                else  //marker SOT found first
                    state = ST_SOT_FOUND;
            break;   
            case ST_SOI_FOUND:
                start_pos = pchr_i - text + strlen(START_OF_INSTRACTION);
                //find EOI - end of instraction
                pchr_i = strstr(&text[loc_idx], END_OF_INSTRACTION);
                if (start_found && pchr_i != NULL)
                {
                    end_pos = pchr_i - text;
                    //copy the found block
                    memcpy(buf, &text[start_pos], (end_pos - start_pos));
                    buf[(end_pos - start_pos)] = '\0';
                    *text_type = TXT_TYPE_INSTRACTION;
                    *idx = end_pos + strlen(END_OF_INSTRACTION);
                    return PARSE_SUCCESS;
                }
            break;
            case ST_SOT_FOUND:
                start_pos = pchr_t - text + strlen(START_OF_TEST);
                //find EOT - end of test
                pchr_t = strstr(&text[loc_idx], END_OF_TEST);
                if (start_found && pchr_t != NULL)
                {
                    end_pos = pchr_t - text;
                    //copy the found block
                    memcpy(buf, &text[start_pos], (end_pos - start_pos)); 
                    buf[(end_pos - start_pos)] = '\0';
                    *text_type = TXT_TYPE_TEST;
                    *idx = end_pos + strlen(END_OF_TEST);
                    return PARSE_SUCCESS;
                }
            break;      
        }
    }
    return PARSE_FAIL; 
}

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

Откуда: Нижневартовск
Сообщений: 1882
jenya7
так на state machine.
наверно так все таки есть выигрыш и по speed и по size.

не особо

ты только логику верхнего уровня загнал в автомат (и то вопрос)

самое плохое место на нижнем уровне
  //find SOI - start of instraction
                pchr_i = strstr(&text[loc_idx], START_OF_INSTRACTION);
                //find SOT - start of test
                pchr_t = strstr(&text[loc_idx], START_OF_TEST);
11 янв 17, 14:08    [20093713]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
Dima T
Member

Откуда:
Сообщений: 10927
Не понятно что должно происходить при нарушении порядка начал и концов, например
"SOI Happy SOT New EOT SOT Year EOI SOI Folks EOI ";

Сделал игнорирование таких некорректно оформленных блоков.
Еще у тебя никак не задается размер буфера, что чревато выходом за его пределы.
+ Исходник
// Возвращает указатель на конец найденного блока
const char* parse(const char* text, char* buf, size_t buf_size) {
	char type = 0;
	char* b = buf;
	size_t s = buf_size;
	const char* p = text;
	for(;*p != 0; p++) {
		if(p[0] == 'S' && p[1] == 'O' && (p[2] == 'I' || p[2] == 'T')) { // Проверка начала блока
			if (type != 0) { // Начало следующего блока без окончания текущего, начинаем сначала
				b = buf;
				s = buf_size;
			}
			type = p[2];
			p += 2;
		} else if(type) { // Пишем в буфер
			if (p[0] == 'E' && p[1] == 'O' && (p[2] == 'I' || p[2] == 'T')) { // Проверка конца блока
				if(type != p[2]) { // конец блока не того типа
					b = buf;
					s = buf_size;
					type = 0;
				} else {
					*b = 0;
					return p + 3;
				}
			} else if(s > 1) { // есть место в буфере
				*b = *p;
				s--;
				b++;
			}
		}
	}
	*b = 0;
	return NULL;
}

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;
}
11 янв 17, 14:14    [20093759]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

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

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

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

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

Откуда:
Сообщений: 10927
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

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

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

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

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

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

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

Откуда: Санкт-Петербург
Сообщений: 662
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

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

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

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

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

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


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

Откуда: Санкт-Петербург
Сообщений: 662
Изопропил
Пётр Седов
Так вы, 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

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

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

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


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

Откуда: Санкт-Петербург
Сообщений: 662
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 '
16 янв 17, 05:20    [20108867]     Ответить | Цитировать Сообщить модератору
 Re: Найти текстовые блоки разного типа в С.  [new]
jenya7
Member

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