Помогите разпарсить строку.

Тема в разделе "Arduino & Shields", создана пользователем Alexey Zhigalo, 12 июл 2016.

  1. Всем доброго времени суток.
    Возникла необходимость разпарсить строку.

    Если входящая строка = #r1_t=25;
    Код (C++):
    void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
      String comands = "#r1_t=25;";
      Serial.println(comands.substring(comands.indexOf("#r1_t=")+6,comands.indexOf(";")));
      delay(500);
    }
    То выводит:
    С одной командой работает нормально, а вот с несколькими не работает.

    Если входящая строка = #r1_t=25; #r2_t=18;
    Код (C++):
    void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
      String comands = "#r1_t=25; #r2_t=18;";
      Serial.println(comands.substring(comands.indexOf("#r1_t=")+6,comands.indexOf(";")));
      Serial.println(comands.substring(comands.indexOf("#r2_t=")+6,comands.indexOf(";")));
      delay(500);
    }
    То выводит:
    А должно:
    При чем, входящая строка может быть и с другими командами, такими как #status; #temp; #all_off; и т.д
    Помогите, пожалуйста.
     
  2. DIYMan

    DIYMan Guest

    Сперва тебе надо разбить строку по разделителям (в твоём случае это ';'), потом уже каждую из этих подстрок разбирать. Ближайший аналог, который напрашивается на сравнение - элементы URI-запроса:

    /index.php?param1=a&param2=qwerty&param3=12345

    То же самое, только разделитель '&'.
     
  3. Vetrinus

    Vetrinus Гик

    Выше сказано правильно, позволю себе немного дополнить.
    У тебя есть подстрока #r1_t=25, с помощью strtok отрезаешь (strtok(substring, "=")) часть строки, отвечающую за название команды (или переменной, не совсем понял, что там именно у тебя). Далее, ты можешь сравнить эту подстроку с уже известными тебе типами команд, чтобы понять, что именно тебе пришло. Потом ты еще раз используешь strtok(substring, NULL), и передвигаешь указатель на само значение, которое ты можешь конвертировать, например с помощью метода atoi.
    P.S. Не знаю, может ли strtok взаимодействовать с объектом класса String, но, что-то мне подсказывает, что может. В ином случае нужно будет переделать форму хранения строки под char массив
     
  4. Сегодня решил переписать проект.
    Сравнивает, что пришло в терминал.
    Вот часть кода.
    Код (C++):
    #include <string.h>

    void setup()
    {
      Serial.begin(9600);
    }
    void loop()
    {
      if (Serial.available())
        check(Serial.readString());
    }

    void check(String com)
    {
      int str_len = com.length() + 1;
      char str[str_len];
      com.toCharArray(str,str_len);
      char* pch;
      pch = strtok (str," \n");
      while (pch != NULL)
      {
        if((String)pch == "#r1_on;")
        {
         digitalWrite(13,1);
        }
        if((String)pch == "#r1_off;")
        {
         digitalWrite(13,0);
        }
        pch = strtok (NULL, " \n");
      }
    }
    Как бы если в терминал пришла команда, то событие обрабатывается.
    Но, надо сравнивать команды типа этого, "#r1_t=" и т.д.

    Пробовал отсекать все что перед равно, строка
    Код (C++):
    strtok(s,tr"=");
    Но выводит только "#r1_t".
    А надо сравнивать "#r1_t="

    Так как без равно могут быть и другое, например "#r1_t_off;"
    Как распарсить строку, с равно, если оно присутствует ?
     
  5. Vetrinus

    Vetrinus Гик

    Попробуйте парсить в ветвлениях. К примеру, порезали на подстроки. Теперь ищите знак "=". Если strtok вернул NULL, значит разделителя тут нет, и парсить нужно по другому.
    И приведите, пожалуйста, полный экземпляр подстроки с = и без, чтобы проще понимать было.
     
  6. Как найти "=" ?
    В каждой подстроке, перебирать символы ?
    Если есть "=" то, парсить до "=" и полсе "=" до ";" ?

    Команд много, но для данной, "#r1_on;" "#r1_off;" "#r1_t=25;"
    25 в этом случае, переменное значение.

    В место "#r1" может быть от 1 до 16.
     
  7. Vetrinus

    Vetrinus Гик

    Ну как вариант:
    Код (C++):

    if(strtok(str, "=")!=NULL){
    strtok(str, "0 1 2 3 4 5 6 7 8 9");
    int value=atoi(strtok(str, NULL));
     
    UPD. Вообще, наверное не надо так делать. При первом вызове указатель изменится, и будет ошибка. Будет правильнее для проверки наличия в подстроке = использовать не strtok, а что-нибудь вроде этого:
    Код (C++):

    int index=0;
    while(index<sizeof(string)){
    if(str[index]=="="){
    strtok(str, "0 1 2 3 4 5 6 7 8 9");
    int value=atoi(strtok(str, NULL));
    break;
    }
    }
     
     
    Последнее редактирование: 14 июл 2016
  8. Я символ равно пытаюсь найти вот так:
    Код (C++):
     if(((String)pch).indexOf("=") !=  -1)
      {
      }
    Далее парсим до равно,
    Код (C++):
     if((String)(strtok(pch,"=")) == "#r1_t")
    {

    }
    Но вот проблема, Strok переписывает переменную pch, а не просто отбрасывает лишнее.
     
    Последнее редактирование: 14 июл 2016
  9. Vetrinus

    Vetrinus Гик

    Ну, можно организовать так, что вам будет безразлично, сбрасывает он переменную, или нет. Объясните, чем именно вам это мешает?
    Или сохраняйте указатели в разные переменные
     
  10. Алгоритм примерно такой:

    Если в подстроке присутствует знак = , то:
    Парсим все до равно.
    Если то что до равно, == команде, например "#r1_t"
    То, целую подстроку, в данном случае "#r1_t=25;"
    Парсим от '=' до ';'
    И получаем 25

    Дальше обрабатываем действие.
     
  11. Я не могу понять, почему strtok() переписывает переменную.

    Я объявил еще одну переменную.
    char* tmp = pch;

    Потом, сравниваем. ели да, то выводим pch.
    Код (C++):
    if((String)strtok(tmp,"=") == "#r1_t")
      {
           Serial.println(pch);
      }
     
    И выводит отпарсиную строку, хотя выводим переменную pch которая не должна меняться.
    А парсили строку tmp.

    Какой то бред в с++.
    На C# все намного легче.
     
  12. DIYMan

    DIYMan Guest

    Дайте полную входную строку и результат, который вы хотите получить на выходе.
     
  13. Входная строка может меняться. В данном случае обрабатывается одна команда.

    Если входная строка "#r1_t=25;"
    если присутствует "#r1_t" то надо получить 25.

    Если входная строка "#r4_t=15;"
    если присутствует "#r4_t" то надо получить 15.
     
  14. DIYMan

    DIYMan Guest

    У вас входная строка всегда из одной команды?
     
  15. DIYMan

    DIYMan Guest

    Если входная строка всегда из одной команды, то примерно так (считаем, что все переменные, в которые надо записывать значения, имеют тип int):
    Код (C++):

    typedef struct
    {
     int* var; // адрес переменной, в которую записывать значение
     const char* command; // команда, по приходу которой в переменную запишется нужное значение
    } t_link;

    int firstVariable;
    int secondVariable;

    t_link links[] = {
      {&firstVariable, "#r1_t"}
    , {&secondVariable, "#r4_t"}
    , {NULL, NULL} // заглушка
    };

    void updateVariables(const char* incomingCommand)
    {
       byte cntr = 0;
       while(links[cntr].var)
       {
          if(strstr(incomingCommand,links[cntr].command) == incomingCommand)
          {
                const char* eqPtr = strstr (incomingCommand + strlen(links[cntr].command), "=");
                if(eqPtr)
                {
                     eqPtr++;
                     *(links[cntr].var) = atoi(eqPtr);
                }
          }
           cntr++;
       }
    }

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