Парсинг массива char

rene
Offline
Зарегистрирован: 21.01.2014

Доброго времени стуок!

Задача, распарсить массив символов, не используя сторонние библиотеки.

Если на входе получаю GET / HTTP/1.1, то пропускаем такой заголовок

Елси же заголовок имеет вид GET /favicon.ico HTTP/1.1, то это запрос на скачивание файла favicon.ico

Опыт у меня не большой, попытался написать свой парсер, но в итоге застопорился на указателях. Учится на много быстрее на конкретных примерах, подскажите наиболее рациональный путь решения задачи.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

а сколько всего вариантов на входе может быть ?

rene
Offline
Зарегистрирован: 21.01.2014

SU-27-16 пишет:

а сколько всего вариантов на входе может быть ?

На входе может быть что угодно, но мы ищем запрос GET

Если подобный запрос найден, смотрим что идет поле него

Если GET / HTTP/1.1, то это пустой заголовок, пропускаем, если же после слеша "/" не пробел -  это запрос какого то файла, который и надо распарсить и затем считать с SD карты.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

убираем все пробелы

если после GET/ >>>>>> HTTP......... - пропуск

если после GET/ >>>>>> не HTTP......... - то после GET/ до / - это нужная подстрока ?

rene
Offline
Зарегистрирован: 21.01.2014

SU-27-16 пишет:

убираем все пробелы

если после GET/ >>>>>> HTTP......... - пропуск

если после GET/ >>>>>> не HTTP......... - то после GET/ до / - это нужная подстрока ?

если после GET/ >>>>>> HTTP......... - пропуск

Да

если после GET/ >>>>>> не HTTP......... - то после GET/ до / - это нужная подстрока

Нет.

Значение между GET / и HTTP это и есть имя файла, HTTP не должно входить в имя

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

и вам в итоге нужен признак что это запрос и имя файла ?

rene
Offline
Зарегистрирован: 21.01.2014

SU-27-16 пишет:

и вам в итоге нужен признак что это запрос и имя файла ?

И то и другое.  Сначала ищем GET, после нахождения которого выдергиваем имя файла

pastry777
Offline
Зарегистрирован: 16.01.2014

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

если нужно именно выдергнуть имя файла,то соответственно,если после слеша не пробел,начинаем набивать наш массив символов до тех пор пока не появится точка(если только имя) или пробел,если имя с расширением..ну вы поняли=)

rene
Offline
Зарегистрирован: 21.01.2014

pastry777 пишет:

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

Именно так, я хотел увидеть рабочий пример, т.е. как это реализуется на профессиональном уровне. Хотел увидеть код

pastry777
Offline
Зарегистрирован: 16.01.2014

у меня у самого не хватает знаний по char,не знаю как его "набивать"=)со String помог бы...

sva1509
Offline
Зарегистрирован: 07.12.2012

Не понял, вы хотите продублировать стандарные функции stdlib ?

В Си есть достаточно обширные средства анализа строки, вы хотите написать свои ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

sva1509 пишет:

Не понял, вы хотите продублировать стандарные функции stdlib ?

В Си есть достаточно обширные средства анализа строки, вы хотите написать свои ?

и моя тоже хочет :) , но вот такая запарка...

String inString1 = "0123456789GET3456789";
String inString2 = "012345678901HTTP6789";
String inString3 = " ET / kjdfvkjh verver GET / favicon.ico HTTP/ 1.1 vver eve ";
String outString;
String *inStr;
//==============================================================================
void setup()
{                
   Serial.begin( 9600 );
}
//==============================================================================
void loop()
{
  inStr = & inString1;
  outString = Parse( inStr );
//  Serial.println( outString );

}
//==============================================================================
String Parse( String *str )
{
  int n;
  int comp; 
  int strLength;
  String tempStr;
  String subStr;
  String findStrGET = "GET";
  String findStrHTTP = "HTTP";
//  char findStrGET[ ] = "GET";
//  char findStrHTTP[ ] = "HTTP";
  tempStr = *str;
  
  Serial.println( "============================================" );
  
  n = 0;
  while( tempStr[ n ] != NULL )
    {
      n++;
    }
  strLength = n;
// в strLength длина строки ---------------------------->
// поиск "GET"
  n = 0;
  comp = 1;
//  while( comp != 0 )
//  for ( int i = 0; comp != 0; i++ )
  for ( int i = 0; i < strLength - 4 ; i++ )
    {
      subStr = tempStr.substring( i , i + 3 );
      Serial.println( subStr );
      Serial.println( findStrGET );
//      comp = tempStr.equals( findStrGET );               // не работает
//      comp = tempStr.equals( "GET" );                    // не работает
//      comp = tempStr.compareTo( findStrGET );            // не работает
//      comp = tempStr.compareTo( "GET" );                 // не работает
      Serial.print( "             comp " ); Serial.println( comp );
      Serial.print( " n_1 " ); Serial.println( n );
      n++;
      Serial.print( " n_2 " ); Serial.println( n );
    }
// в n -  ---------------------------->
  Serial.print( " n_3 " ); Serial.println( n );
  
  
  
  
//  Serial.print( " G in n = " );   Serial.print( n ); Serial.print( " " ); Serial.println( tempString[ n ] );
  return tempStr;
}
//==============================================================================

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

sva1509
Offline
Зарегистрирован: 07.12.2012

советую отказатся от объекта String и смотреть в сторону стандартной либы <string.h>. А конкретней в сторону strstr();

вот чем можно воспользоваться:

http://www.cplusplus.com/reference/cstring/

если я вас правильно понял.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

спасибо ! :) , а то всю ночь убил.... будем изучать...

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012
char inString1[ ] = "0123456789GET3456789";
char inString2[ ] = "012345678901HTTP6789";
char inString3[ ] = " ET / kjdfvkjh verver GET / favicon.ico HTTP/ 1.1 vver eve ";
char outString[ ] = "";
//==============================================================================
void setup()
{                
   Serial.begin( 9600 );
}
//==============================================================================
void loop()
{
  char *inStr = inString1;
  char *outStr;
//  outString = Parse( *inStr );        // ??????????????????
  Serial.println( "abc" );
  Serial.println( outString );
}
//==============================================================================
char Parse( char *str )
{
  char tempStr[ ] = "";
//  tempStr = *str;
//  return tempStr;                       // ??????????????????
  return 'd';
}
//==============================================================================

.....опять :( , всё - спать, потом читать

rene
Offline
Зарегистрирован: 21.01.2014

sva1509 пишет:

Не понял, вы хотите продублировать стандарные функции stdlib ?

В Си есть достаточно обширные средства анализа строки, вы хотите написать свои ?

Хотел, но передумал, не так то это просто оказывается.

Datak
Offline
Зарегистрирован: 09.10.2014

SU-27-16 пишет:

вот такая запарка...



















.....

String Parse( String *str )
{
  .....

  tempStr = *str;
 
  .....
}

Без звёздочки, по-моему: tempStr = str;

А всё из-за привычки писать String  *str, вместо String*  str. :)

Не, я понимаю, тут кто как привык - переубеждать никого не собираюсь. Но сами же видите, к чему это приводит.

 

Насчёт разбора этой строки. По HTTP протоколу, формат у неё на самом деле такой:

<тип_запроса><пробел><идентификатор_ресурса><пробел><версия_протокола><конец_строки>

тип_запроса - GET или POST или HEAD... или даже ещё что-то - не помню.

идентификатор_ресурса - собственно, название того, что клиент хочет получить от сервера. Пробелов в нём, внутри, быть не может, не бойтесь - по протоколу не положено.

версия_протокола - тут всё понятно: HTTP, и циферки какие-нибудь.

конец_строки - если не ошибаюсь - символы '\r' и '\n'.

Соответственно, пробелы при разборе не выбрасываются, а используются для разделения строки на 3 подстроки.

Во второй подстроке получим или имя файла, или только слэш.

rene
Offline
Зарегистрирован: 21.01.2014

Помогите разобраться с функцией strtok

На powershell после разбиения подстроки помещаются в массив из которого можно выдернуть любой элемент, например:

$a = "GET /favicon.ico HTTP/1.1".split(" /")
echo $a[2]

В ответ получаем favicon.ico

А вот этот код ардуино никак не пойму:

char* str = "GET /favicon.ico HTTP/1.1";
str = strtok(str," /");

После выполнения кода в str хранится "GET"

Если далее выполнить команду

str = strtok(NULL, " /");

Получим favicon.ico

Что то логика от меня ускользает

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Всё правильно эта функция так и работает. Если первым параметром указан NULL то функция продолжает искать с того места где остановилась при предыдущем вызове. Т.е. если надо вторую лексему то надо вызвать strtok два раза, второй раз м NULL, если третью лексему надо то еще раз вызываем с NULL и т.д.

rene
Offline
Зарегистрирован: 21.01.2014

Спасибо!

rene
Offline
Зарегистрирован: 21.01.2014

Подскажите, как можно собирать char в строки?

  char str[] = "abc";
  str = str + "d";

Так не получается. Длина строки не известна, поэтому не могу объявить фиксированный массив.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

strcat , наверное...

char * strcat ( char * destination, const char * source );
Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Как вариант, хотя String тут не рекомендовали использовать

String str="";
str += 'A';
str += 'B';

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

 char * strcat ( char * destination, const char * source );это не из String , а из http://www.cplusplus.com/reference/cstring/ , также как и strtok(str," /");

Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:

Подскажите, как можно собирать char в строки?



  char str[] = "abc";
  str = str + "d";

Так не получается. Длина строки не известна, поэтому не могу объявить фиксированный массив.

Раэмер буфера надо задавать с запасом, по максимуму.

А если хочется попроще - можно использовать другой тип данных: String

  String str = "abc";
  str = str + "d";

Этот тип уже заранее "обучили" операции сложения, и ещё некоторым другим.
Правда, скорее всего, прошивка займёт чуть больше места, и работать будет немного медленней - зато программировать так проще.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Да это я неграмотно написал :) Как вариант это три строчки которые я написал, а вариант потому что стринг не рекомендовали использовать :) 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

rene пишет:

Подскажите, как можно собирать char в строки?

  char str[] = "abc";
  str = str + "d";

Так не получается. Длина строки не известна, поэтому не могу объявить фиксированный массив.

из той же библиотеки - size_t strlen ( const char * str );

rene
Offline
Зарегистрирован: 21.01.2014
  Serial.begin(9600);
  char str[] = "abc";
  strcat (str, "d");
  Serial.println(str);

Так получается.

Наивыший уровень развития личности (по пирамиде Маслоу) - Потребность в самоактуализации: реализация своих целей, способностей, развитие собственной личности. Я лично считаю что есть более высокий уровень развития - потребность делится накопленным опытом. На данном форуме я это вижу, спасибо!

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

rene пишет:

Я лично считаю что есть более высокий уровень развития - потребность делится накопленным опытом. На данном форуме я это вижу, спасибо!

 полностью присоединяюсь к мнению! :)

sva1509
Offline
Зарегистрирован: 07.12.2012

2rene приблизительно так :

char strbuf[50];  // резервируем буфер для формирования строки

strcpy(strbuf,"GET");  // копируем первый элемент с начала строки
strcat(strbuf," /file.sav"); // добавляем в буфер дополнительную строку

 

Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:








  Serial.begin(9600);
  char str[] = "abc";
  strcat (str, "d");
  Serial.println(str);

Так получается.

Получается, но это неправильно. Этот код лезет в чужую память. По чистой случайности он там не убил ничего важного.

 

sva1509 пишет:






char strbuf[50];  // резервируем буфер для формирования строки

strcpy(strbuf,"GET");  // копируем первый элемент с начала строки
strcat(strbuf," /file.sav"); // добавляем в буфер дополнительную строку

Вот так делайте. Или через String - он сам будет следить за правильным выделением памяти.

 

rene
Offline
Зарегистрирован: 21.01.2014

То что я и искал, спасибо, а стрингом я пытаюсь теперь не пользоваться, ибо тут сказали что это моветон

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Дурной тон или нет, определяет не публика в интернете, а задачи и потребности конкретного проекта.

rene
Offline
Зарегистрирован: 21.01.2014
char strbuf[50] = "123";
char c = 49;
strcat(strbuf, c);

не получается прицепить char к char*

rene
Offline
Зарегистрирован: 21.01.2014
  Serial.begin(9600);
  char strbuf[50] = "123";
  char c = 49;
  char* a = &c;
  strcat(strbuf, a);
  Serial.println(strbuf);

Так программа вообще ничего не выводит, пустой экран

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015
так должно работать
char strbuf[50] = "123";
char c = 49;
strcat(strbuf, &c);

 

rene
Offline
Зарегистрирован: 21.01.2014

Пробовал, это аналого моего char* a = &c; тоже пустой экран

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Я только что у себя на ардуине пробовал, работает...

Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:

не получается прицепить char к char*

Может и не обязательно?

char strbuf[50] = "123";
char c = "1";
strcat(strbuf, c);

Или можно более другими способами, например вручную:

char strbuf[50] = "123";
char* pEnd = strbuf + strlen( strbuf ); // получили указатель на конец строки
*pEnd++ = '1';                          // добавили к строке символ '1' (код 49)
*pEnd = 0;                              // и обязательно добавили завершающий строку ноль

Не проверял, правда, но вроде нигде не ошибся.

Datak
Offline
Зарегистрирован: 09.10.2014

strcat'ом нельзя цеплять &c, потому что strcat ожидает на входе строку, которая обязательно должна заканчиваться нулём.

Если написать strcat(strbuf, &c); - strcat попытается прицепить к строке то что лежит в  c,  и всё что лежит в памяти после этого  c, до первого случайно встретившегося нуля. Результат получится совсем не тот, который хотелось, да и буфер скорее всего переполнится.

 

rene
Offline
Зарегистрирован: 21.01.2014

Penni пишет:

Я только что у себя на ардуине пробовал, работает...

Странно, вот полный скетч

void setup(){
  Serial.begin(9600);
  char strbuf[50] = "123"; 
  char c = 49; 
  strcat(strbuf, &c); 
  Serial.println(strbuf);
}

void loop(){
}

Ошибится вроде как сложно, но у меня в терминале пустой экран. Mega 2560

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

У меня ваш скетч работает тоже мега 2560

Datak
Offline
Зарегистрирован: 09.10.2014

Неправильный это скетч. Я там, выше, объяснял почему. Могу ещё, если хотите.

Только не знаю, что там не понятно?

rene
Offline
Зарегистрирован: 21.01.2014

Datak пишет:

strcat'ом нельзя цеплять &c, потому что strcat ожидает на входе строку, которая обязательно должна заканчиваться нулём.

Если написать strcat(strbuf, &c); - strcat попытается прицепить к строке то что лежит в  c,  и всё что лежит в памяти после этого  c, до первого случайно встретившегося нуля. Результат получится совсем не тот, который хотелось, да и буфер скорее всего переполнится.

к сожалению я не могу прицепить просто символ, в оригинальном скетче команда выглядит так:

char c = client.read(); // читаем поступающие от клиента символы

т.е. на входе я получаю код символа

 

rene
Offline
Зарегистрирован: 21.01.2014

Datak пишет:

Неправильный это скетч. Я там, выше, объяснял почему. Могу ещё, если хотите.

Только не знаю, что там не понятно?

Я уже понял, попробовал так, не получается

  char c[1];
  char strbuf[50] = "123"; 
  c[0] = 49;
  c[1] = 0;
  char* a = &c;
  strcat(strbuf, a);

Нужно найти способ прицепить 0 после кода символа, или же сразу код конвертировать в символ

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

strncat(strbuf, a, 1) и никакая чужая память не затронется.

rene
Offline
Зарегистрирован: 21.01.2014

Datak пишет:

Неправильный это скетч. Я там, выше, объяснял почему. Могу ещё, если хотите.

Только не знаю, что там не понятно?

 

  char strbuf[50] = "123"; 
  char c = "1"; 
  strcat(strbuf, c); 

Не рабочий код

rene
Offline
Зарегистрирован: 21.01.2014
  char strbuf[50] = "123"; 
  char c = 49; 
  strncat(strbuf, &c, 1); 

Да! Это оно! Спасибо

rene
Offline
Зарегистрирован: 21.01.2014
  char* strbuf = "000000000000000000000000000000"; // резервируем память
  char c = 49;
  *strbuf = 0; // перемещаем указатель на начало строки
  strbuf = "123";
  strncat(strbuf, &c, 1); // добавляем символ "1" к strbuf

Скажите, а такой код может считаться приемлемым? Вроде это позволяет не вводить дополнительных переменных для преобразования char в char* при использовании strtok

Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:











  char strbuf[50] = "123"; 
  char c = "1"; 
  strcat(strbuf, c); 

Не рабочий код

Не придирайтесь. :)









  char strbuf[50] = "123"; 
  char c[] = "1"; 
  strcat(strbuf, c); 


Или char* c = "1"; Или, в конце концов, так:  strcat(strbuf, "1");

ЗЫ: strncat, конечно, тоже правильно, и даже правильней в несколько раз. :)

 

Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:

Я уже понял, попробовал так, не получается











  char c[1];
  char strbuf[50] = "123"; 
  c[0] = 49;
  c[1] = 0;
  char* a = &c;
  strcat(strbuf, a);

Не получается, потому что  в 5 строке должно быть char* a = c; (без амперсанда). И опять же, лишняя  она - можно написать сразу: strcat(strbuf, c);

И ещё - в первой строке должно быть char c[2];