├── .gitattributes ├── .github └── workflows │ └── tg-send.yml ├── LICENSE ├── README.md ├── README_EN.md ├── examples ├── test │ └── test.ino ├── testUnicode │ └── testUnicode.ino ├── testUrl │ └── testUrl.ino └── testUtils │ └── testUtils.ino ├── keywords.txt ├── library.properties └── src ├── GParser.h └── utils ├── parseUtils.cpp ├── parseUtils.h ├── unicode.cpp ├── unicode.h ├── url.cpp └── url.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/tg-send.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Telegram Message 3 | on: 4 | release: 5 | types: [published] 6 | jobs: 7 | build: 8 | name: Send Message 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: send telegram message on push 12 | uses: appleboy/telegram-action@master 13 | with: 14 | to: ${{ secrets.TELEGRAM_TO }} 15 | token: ${{ secrets.TELEGRAM_TOKEN }} 16 | disable_web_page_preview: true 17 | message: | 18 | ${{ github.event.repository.name }} v${{ github.event.release.tag_name }} 19 | ${{ github.event.release.body }} 20 | https://github.com/${{ github.repository }} 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AlexGyver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![latest](https://img.shields.io/github/v/release/GyverLibs/GParser.svg?color=brightgreen)](https://github.com/GyverLibs/GParser/releases/latest/download/GParser.zip) 2 | [![PIO](https://badges.registry.platformio.org/packages/gyverlibs/library/GParser.svg)](https://registry.platformio.org/libraries/gyverlibs/GParser) 3 | [![Foo](https://img.shields.io/badge/Website-AlexGyver.ru-blue.svg?style=flat-square)](https://alexgyver.ru/) 4 | [![Foo](https://img.shields.io/badge/%E2%82%BD%24%E2%82%AC%20%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B0%D1%82%D1%8C-%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B0-orange.svg?style=flat-square)](https://alexgyver.ru/support_alex/) 5 | [![Foo](https://img.shields.io/badge/README-ENGLISH-blueviolet.svg?style=flat-square)](https://github-com.translate.goog/GyverLibs/GParser?_x_tr_sl=ru&_x_tr_tl=en) 6 | 7 | [![Foo](https://img.shields.io/badge/ПОДПИСАТЬСЯ-НА%20ОБНОВЛЕНИЯ-brightgreen.svg?style=social&logo=telegram&color=blue)](https://t.me/GyverLibs) 8 | 9 | |⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️

**ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ [StringUtils](https://github.com/GyverLibs/StringUtils), ОНА ИМЕЕТ БОЛЬШЕ ВОЗМОЖНОСТЕЙ**

⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️| 10 | | --- | 11 | 12 | # GParser 13 | Простой и быстрый парсер строк в отдельные подстроки и числа для Arduino 14 | - Работает с указанным буфером (строкой), не создаёт свой 15 | - Разделяет строку на подстроки по указанному символу 16 | - Позволяет обращаться к подстрокам, переводить их в числа и сравнивать со строками 17 | - Доступ к подстрокам через [] 18 | - Может распарсить строку в массив int или byte 19 | 20 | ### Совместимость 21 | Совместима со всеми Arduino платформами (используются Arduino-функции) 22 | 23 | ## Содержание 24 | - [Установка](#install) 25 | - [Инициализация](#init) 26 | - [Использование](#usage) 27 | - [Пример](#example) 28 | - [Версии](#versions) 29 | - [Баги и обратная связь](#feedback) 30 | 31 | 32 | ## Установка 33 | - Библиотеку можно найти по названию **GParser** и установить через менеджер библиотек в: 34 | - Arduino IDE 35 | - Arduino IDE v2 36 | - PlatformIO 37 | - [Скачать библиотеку](https://github.com/GyverLibs/GParser/archive/refs/heads/main.zip) .zip архивом для ручной установки: 38 | - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) 39 | - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) 40 | - Распаковать и положить в *Документы/Arduino/libraries/* 41 | - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив 42 | - Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 43 | ### Обновление 44 | - Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи 45 | - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить" 46 | - Вручную: **удалить папку со старой версией**, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам! 47 | 48 | 49 | 50 | ## Инициализация 51 | ```cpp 52 | // передать char array строку, можно указать символ разделитель (по умолч ',') 53 | GParser (char* data); 54 | GParser (char* data, char newDiv = ','); 55 | ``` 56 | 57 | 58 | ## Использование 59 | ### Класс GParser 60 | ```cpp 61 | void setDiv(char newDiv); // указать символ разделитель 62 | void clear(); // освободить буфер 63 | int amount(); // количество разделённых данных в пакете 64 | int split(); // разделить строку на подстроки 65 | int32_t getInt(int num); // получить инт из выбранной подстроки 66 | float getFloat(int num); // получить float из выбранной подстроки 67 | bool equals(int num, const char* comp); // сравнить подстроку с другой строкой 68 | int parseBytes(byte* data); // распарсить на байты 69 | int parseInts(int* data); // распарсить на инты 70 | int parseLongs(long* data); // распарсить на лонги 71 | void restore(); // восстановить исходный вид строки (вернуть разделители) 72 | ``` 73 | 74 | ### Отдельные функции парсинга 75 | См. пример **testUtils** 76 | 77 | ```cpp 78 | // количество подстрок в списке list с разделителем div 79 | uint8_t GP_listSize(char* list, char div = ','); 80 | 81 | // разделить список list с разделителем div на подстроки (см. пример) 82 | char* GP_splitList(char* list, char div = ','); 83 | 84 | // получить номер, под которым name входит в list с разделителем div. -1 если не входит 85 | int8_t GP_inList(char* name, char* list, char div = ','); 86 | 87 | // преобразовать int в строку (работает в 3-10 раз быстрее ltoa + основание) 88 | void GP_numToChar(int32_t n, char* buf, uint8_t base); 89 | 90 | // преобразовать float в строку 91 | void GP_floatToChar(double f, char *buf, uint8_t decimals); 92 | 93 | // преобразовать строку в число 94 | int32_t GP_charToNum(char* buf, uint8_t base); 95 | 96 | // преобразовать строку в float 97 | double GP_charToFloat(char* buf); 98 | 99 | // получить число под индексом idx в списке list с разделителем div 100 | int GP_numFromList(char* list, int idx, char div = ','); 101 | 102 | // переписать список list с разделителем div в массив чисел data размером size 103 | uint8_t GP_listToNum(char* list, int* data, uint8_t size, char div = ','); 104 | 105 | // преобразовать текстовый цвет (0x, #) в число 106 | uint32_t GP_decodeColor(char* hex); 107 | ``` 108 | 109 | ### Unicode 110 | См. пример **testUnicode** 111 | 112 | ```cpp 113 | char* GP_uniencode(int32_t c, char* s); // код unicode в char[5] 114 | String GP_uniencode(uint16_t c); // код unicode в String 115 | uint16_t GP_unistrlen(char* data); // длина unicode строки в кол-ве символов 116 | ``` 117 | 118 | ### Url encode/decode 119 | См. пример **testUrl** 120 | 121 | ```cpp 122 | void GP_urlencode(const String& s, String& dest); // urlencode из String в String 123 | String GP_urlencode(const String& s); // urlencode из String в String (возврат) 124 | String GP_urldecode(const String& s, String& dest); // urldecode из String в String 125 | String GP_urldecode(const String& s); // urldecode из String в String (возврат) 126 | ``` 127 | 128 | 129 | ## Пример 130 | Остальные примеры смотри в **examples**! 131 | ```cpp 132 | // тест парсера строк 133 | #include 134 | 135 | void setup() { 136 | Serial.begin(9600); 137 | 138 | // ==================== ПРИМЕР 1 ====================== 139 | // строка для примера 140 | // данные разделены разделителем, например запятой 141 | // могут быть получены из Serial/UDP/TCP/MQTT итд 142 | char str[] = "1234,3.14,hello,4567,lolkek,qwerty"; 143 | 144 | // кормим строку парсеру, указываем разделитель (умолч. запятая) 145 | GParser data(str, ','); 146 | 147 | // разделяем 148 | // ВНИМАНИЕ! Операция "ломает" строку, заменяя разделители на NULL 149 | int am = data.split(); 150 | // получаем количество данных 151 | 152 | Serial.println(am); // выводим количество 153 | 154 | // можем обратиться к полученным строкам как data[i] или data.str[i] 155 | for (byte i = 0; i < am; i++) Serial.println(data[i]); 156 | 157 | // также можно получить их в виде int и float чисел 158 | // передав индекс строки 159 | Serial.println(data.getInt(0)); 160 | Serial.println(data.getFloat(1)); 161 | 162 | // можно сравнить со строкой (номер парс строки, строка для сравнения) 163 | if (data.equals(2, "hello")) Serial.println("true"); 164 | else Serial.println("false"); 165 | 166 | Serial.println(); 167 | 168 | // ==================== ПРИМЕР 2 ====================== 169 | // быстрый парсинг целочисленных данных с разделителем 170 | char str2[] = "123,456,789,222,333,444"; 171 | GParser data2(str2); // кормим строку парсеру 172 | 173 | // создаём массив с количеством ячеек data2.amount() - столько данных в пакете 174 | int ints[data2.amount()]; 175 | 176 | int am2 = data2.parseInts(ints); // раскидает в указанный массив и вернёт количество 177 | // фактически тут am2 == data2.amount() - количество данных 178 | // выводим 179 | for (byte i = 0; i < am; i++) Serial.println(ints[i]); 180 | } 181 | 182 | void loop() { 183 | } 184 | 185 | ``` 186 | 187 | 188 | ## Версии 189 | - v1.0 190 | - v1.1 - добавлены отдельные инструменты для парсинга 191 | - v1.2 - добавлены ещё инструменты для парсинга 192 | - v1.3 - добавлена возможность восстановить строку 193 | - v1.3.1 - фикс warning 194 | - v1.4 - добавил url и unicode кодирование 195 | - v1.5 - getInt теперь возвращает int32_t 196 | 197 | 198 | ## Баги и обратная связь 199 | При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru) 200 | Библиотека открыта для доработки и ваших **Pull Request**'ов! 201 | 202 | 203 | При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать: 204 | - Версия библиотеки 205 | - Какой используется МК 206 | - Версия SDK (для ESP) 207 | - Версия Arduino IDE 208 | - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде 209 | - Какой код загружался, какая работа от него ожидалась и как он работает в реальности 210 | - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код 211 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | This is an automatic translation, may be incorrect in some places. See sources and examples! 2 | 3 | # Gparser 4 | Simple and fast Parser lines in separate tunes and numbers for Arduino 5 | - works with the indicated buffer (line), does not create its own 6 | - shares the line for tuning according to the specified symbol 7 | - allows you to contact tunes, transfer them into numbers and compare with lines 8 | - Access to tunes through [] 9 | - can rinse the line into the INT or BYTE array 10 | 11 | ## compatibility 12 | Compatible with all arduino platforms (used arduino functions) 13 | 14 | ## Content 15 | - [installation] (# Install) 16 | - [initialization] (#init) 17 | - [use] (#usage) 18 | - [Example] (# Example) 19 | - [versions] (#varsions) 20 | - [bugs and feedback] (#fedback) 21 | 22 | 23 | ## Installation 24 | - The library can be found by the name ** gparser ** and installed through the library manager in: 25 | - Arduino ide 26 | - Arduino ide v2 27 | - Platformio 28 | - [download the library] (https://github.com/gyverlibs/gparser/archive/refs/heads/main.zip) .Zip archive for manual installation: 29 | - unpack and put in * C: \ Program Files (X86) \ Arduino \ Libraries * (Windows X64) 30 | - unpack and put in * C: \ Program Files \ Arduino \ Libraries * (Windows X32) 31 | - unpack and put in *documents/arduino/libraries/ * 32 | - (Arduino id) Automatic installation from. Zip: * sketch/connect the library/add .Zip library ... * and specify downloaded archive 33 | - Read more detailed instructions for installing libraries [here] (https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%BD%D0%BE%BE%BE%BED0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 34 | ### Update 35 | - I recommend always updating the library: errors and bugs are corrected in the new versions, as well as optimization and new features are added 36 | - through the IDE library manager: find the library how to install and click "update" 37 | - Manually: ** remove the folder with the old version **, and then put a new one in its place.“Replacement” cannot be done: sometimes in new versions, files that remain when replacing are deleted and can lead to errors! 38 | 39 | 40 | 41 | ## initialization 42 | `` `CPP 43 | // Transfer Char Array a line, you can specify the Symbol Separate (by the silence ',') 44 | GParser (Char* Data); 45 | Gparser (Char* Data, Char Newdiv = ','); 46 | `` ` 47 | 48 | 49 | ## Usage 50 | ### class GParser 51 | `` `CPP 52 | VOID Setdiv (Char Newdiv);// specify the Symbol Separate 53 | Void Clear ();// Free the buffer 54 | int amount ();// The number of data separated in the package 55 | int split ();// divide the line into tunes 56 | int32_t getint (int num);// Get Inta from the selected tack 57 | Float getfloat (int num);// Get Float from the selected toll 58 | Bool Equals (int num, const char* comp);// Compare the tuning with another line 59 | int Parsebytes (byte* data);// Parish bytes 60 | int parseints (int* data);// Parisulate on Ints 61 | Intselongs (LONG* DATA);// Parish on Longs 62 | VOID restore ();// Restore the original type of line (return the dividers) 63 | `` ` 64 | 65 | ### Separate Parsing Functions 66 | See example ** testils ** 67 | 68 | `` `CPP 69 | // Number of tuning in the list list with DIV separator 70 | uint8_t gp_listsize (char* list, char div = ','); 71 | 72 | // Divide the list of LIST with the DIV separator into tunes (see example) 73 | Char* gp_splitlist (char* list, char div = ','); 74 | 75 | // Get a number under which NAME is included in LIST with the DIV separator.-1 if not included 76 | int8_t gp_inlist (char* name, char* list, char div = ','); 77 | 78 | // Transform int into a line (it works 3-10 times faster LTOA + base) 79 | VOID gp_numtochar (int32_t n, char* buf, uint8_t base); 80 | 81 | // Transform Float into a line 82 | VOID gp_floattoChar (Double F, Char *Buf, Uint8_T Decimals); 83 | 84 | // Transfer the line to the number 85 | int32_t gp_Chartonum (char* buf, uint8_t base); 86 | 87 | // Transform the line into Float 88 | Double gp_Chartofloat (Char* buf); 89 | 90 | // Get the number under the IDX index in the list list with the DIV separator 91 | Ints_numfromlist (Char* List, Intx, Char Div = ','); 92 | 93 | // Re -rewrite the list of LIST with the DIV separator in the DATA size array of SIZE 94 | uint8_t gp_listonum (char* list, int* data, uint8_t size, char div = ','); 95 | 96 | // Transfer text color (0x, #) to the number 97 | uint32_t gp_decodecolor (char* hex); 98 | `` ` 99 | 100 | ### Unicode 101 | See example ** testicode ** 102 | 103 | `` `CPP 104 | Char* gp_unencode (int32_t c, char* s);// Unicode code in Char [5] 105 | String gp_unencode (uint16_t c);// Unicode code in String 106 | uint16_t gp_unistrlen (char* data);// UNICODE Length Line in the number of symbols 107 | `` ` 108 | 109 | ### url encode/decode 110 | See example ** Testurb ** 111 | 112 | `` `CPP 113 | VOID gp_urlencode (Constation String & S, String & Dest);// Urlencode from String to String 114 | String gp_urlencode (const string & s);// Urlencode from String to String (Return) 115 | String GP_urldecode (Constation String & S, String & Dest);// urlDecode from String in String 116 | String GP_urldecode (Const String & S);// urldecode from String to String (Return) 117 | `` ` 118 | 119 | 120 | ## Example 121 | The rest of the examples look at ** Examples **! 122 | `` `CPP 123 | // Parser's Test 124 | #include 125 | 126 | VOID setup () { 127 | Serial.Begin (9600); 128 | 129 | // ======================================================= 130 | // Line for example 131 | // Data is separated by a divider, for example, a comma 132 | // can be obtained from Serial/UDP/TCP/MQTT etc. 133 | Char Str [] = "1234.3.14, Hello, 4567, Lolkek, Qwerty"; 134 | 135 | // feed the line of the parser, indicate the separator (silence) 136 | Gparser data (str, ','); 137 | 138 | // Share 139 | // ATTENTION!The operation "breaks" the line, replacing the dividers with NULL 140 | int am = data.split (); 141 | // Get the amount of data 142 | 143 | Serial.println (AM);// We display the quantity 144 | 145 | // We can turn to the resulting lines as Data [i] or Data.str [i] 146 | for (byte i = 0; i 179 | ## versions 180 | - V1.0 181 | - V1.1 - added individual parsing tools 182 | - V1.2 - Parsing tools added more tools 183 | - v1.3 - added the ability to restore the line 184 | - V1.3.1 - Fix Warning 185 | - v1.4 - added URL and Unicode coding 186 | - V1.5 - Getint now returns int32_t 187 | 188 | 189 | ## bugs and feedback 190 | Create ** Issue ** when you find bugs, but better immediately write to the mail [alex@alexgyver.ru] (mailto: alex@alexgyver.ru) 191 | The library is open for refinement and your ** pull Request ** 'ow! 192 | 193 | 194 | When reporting about bugs or incorrect work of the library, it is necessary to indicate: 195 | - The version of the library 196 | - What is MK used 197 | - SDK version (for ESP) 198 | - version of Arduino ide 199 | - whether the built -in examples work correctly, in which the functions and designs are used, leading to a bug in your code 200 | - what code has been loaded, what work was expected from it and how it works in reality 201 | - Ideally, attach the minimum code in which the bug is observed.Not a canvas of a thousand lines, but a minimum code -------------------------------------------------------------------------------- /examples/test/test.ino: -------------------------------------------------------------------------------- 1 | // тест парсера строк 2 | #include 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | 7 | // ==================== ПРИМЕР 1 ====================== 8 | // строка для примера 9 | // данные разделены разделителем, например запятой 10 | // могут быть получены из Serial/UDP/TCP/MQTT итд 11 | char str[] = "1234,3.14,hello,4567,lolkek,qwerty"; 12 | 13 | // кормим строку парсеру, указываем разделитель (умолч. запятая) 14 | GParser data(str, ','); 15 | 16 | // разделяем 17 | // ВНИМАНИЕ! Операция "ломает" строку, заменяя разделители на NULL 18 | int am = data.split(); 19 | // получаем количество данных 20 | 21 | Serial.println(am); // выводим количество 22 | 23 | // можем обратиться к полученным строкам как data[i] или data.str[i] 24 | for (byte i = 0; i < am; i++) Serial.println(data[i]); 25 | 26 | // также можно получить их в виде int и float чисел 27 | // передав индекс строки 28 | Serial.println(data.getInt(0)); 29 | Serial.println(data.getFloat(1)); 30 | 31 | // можно сравнить со строкой (номер парс строки, строка для сравнения) 32 | if (data.equals(2, "hello")) Serial.println("true"); 33 | else Serial.println("false"); 34 | 35 | data.restore(); // восстановить исходный вид строки (вернуть разделители) 36 | 37 | Serial.println(); 38 | 39 | // ==================== ПРИМЕР 2 ====================== 40 | // быстрый парсинг целочисленных данных с разделителем 41 | char str2[] = "123,456,789,222,333,444"; 42 | GParser data2(str2); // кормим строку парсеру 43 | 44 | // создаём массив с количеством ячеек data2.amount() - столько данных в пакете 45 | int ints[data2.amount()]; 46 | 47 | int am2 = data2.parseInts(ints); // раскидает в указанный массив и вернёт количество 48 | // фактически тут am2 == data2.amount() - количество данных 49 | // выводим 50 | for (byte i = 0; i < am2; i++) Serial.println(ints[i]); 51 | } 52 | 53 | void loop() { 54 | } 55 | -------------------------------------------------------------------------------- /examples/testUnicode/testUnicode.ino: -------------------------------------------------------------------------------- 1 | // тест утилит для парсинга 2 | #include 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | // неправильно посчитает длину строки 7 | Serial.println(strlen("Привет!")); 8 | // правильно посчитает длину строки 9 | Serial.println(GP_unistrlen("Привет!")); 10 | 11 | Serial.println(GP_uniencode(0x27A1)); 12 | } 13 | 14 | void loop() { 15 | } 16 | -------------------------------------------------------------------------------- /examples/testUrl/testUrl.ino: -------------------------------------------------------------------------------- 1 | // тест утилит для парсинга 2 | #include 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | String enc = GP_urlencode("https://kek.ru/#абвг"); 7 | Serial.println(enc); 8 | Serial.println(GP_urldecode(enc)); 9 | } 10 | 11 | void loop() { 12 | } 13 | -------------------------------------------------------------------------------- /examples/testUtils/testUtils.ino: -------------------------------------------------------------------------------- 1 | // тест утилит для парсинга 2 | #include 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | 7 | // список. Данные разделены запятой 8 | char list[] = "123,456,789,abc,def"; 9 | 10 | // ===================== 11 | Serial.println("Split test"); 12 | char* p = list; 13 | GP_splitList(NULL); 14 | while ((p = GP_splitList(list)) != NULL) { 15 | Serial.println(p); 16 | } 17 | Serial.println(); 18 | 19 | // ===================== 20 | Serial.println("InList test"); 21 | Serial.println(GP_inList("abc", list)); 22 | Serial.println(GP_inList("kek", list)); 23 | Serial.println(); 24 | 25 | // ===================== 26 | Serial.println("Num list test"); 27 | Serial.println(GP_numFromList(list, 2)); 28 | Serial.println(); 29 | 30 | // ===================== 31 | Serial.println("Array list test"); 32 | int data[3]; 33 | GP_listToNum(list, data, 3); 34 | for (int i = 0; i < 3; i++) { 35 | Serial.print(data[i]); 36 | Serial.print(','); 37 | } 38 | Serial.println(); 39 | Serial.println(); 40 | 41 | // ===================== 42 | Serial.println("Num to char test"); 43 | char st[30]; 44 | 45 | GP_numToChar(0x123abc, st, HEX); 46 | Serial.println(st); 47 | 48 | GP_numToChar(123456, st, DEC); 49 | Serial.println(st); 50 | 51 | GP_numToChar(0b11100011, st, BIN); 52 | Serial.println(st); 53 | 54 | GP_floatToChar(3.1415, st, 3); 55 | Serial.println(st); 56 | Serial.println(); 57 | 58 | // ===================== 59 | Serial.println("Char to num test"); 60 | int32_t val; 61 | 62 | val = GP_charToNum("AAFF", HEX); 63 | Serial.println(val, HEX); 64 | 65 | val = GP_charToNum("123456", DEC); 66 | Serial.println(val, DEC); 67 | 68 | val = GP_charToNum("11000011", BIN); 69 | Serial.println(val, BIN); 70 | 71 | float valf = GP_charToFloat("3.14"); 72 | Serial.println(valf); 73 | Serial.println(); 74 | 75 | // ===================== 76 | Serial.println("Color test"); 77 | Serial.println(GP_decodeColor("0xFF22"), HEX); 78 | Serial.println(GP_decodeColor("#FF22"), HEX); 79 | Serial.println(GP_decodeColor("FF22"), HEX); 80 | } 81 | 82 | void loop() { 83 | } 84 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For GParser 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | GParser KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | setDiv KEYWORD2 16 | clear KEYWORD2 17 | amount KEYWORD2 18 | split KEYWORD2 19 | getInt KEYWORD2 20 | getFloat KEYWORD2 21 | equals KEYWORD2 22 | parseInts KEYWORD2 23 | parseBytes KEYWORD2 24 | parseLongs KEYWORD2 25 | buf KEYWORD2 26 | str KEYWORD2 27 | restore KEYWORD2 28 | 29 | GP_listSize KEYWORD2 30 | GP_splitList KEYWORD2 31 | GP_inList KEYWORD2 32 | GP_numToChar KEYWORD2 33 | GP_floatToChar KEYWORD2 34 | GP_charToNum KEYWORD2 35 | GP_charToFloat KEYWORD2 36 | GP_numFromList KEYWORD2 37 | GP_listToNum KEYWORD2 38 | GP_decodeColor KEYWORD2 39 | 40 | GP_urlencode KEYWORD2 41 | GP_urldecode KEYWORD2 42 | GP_uniencode KEYWORD2 43 | GP_unistrlen KEYWORD2 44 | 45 | ####################################### 46 | # Constants (LITERAL1) 47 | ####################################### -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=GParser 2 | version=1.5.2 3 | author=AlexGyver 4 | maintainer=AlexGyver 5 | sentence=Fast library for parsing cstring into substrings, urlencode, unicode encode for Arduino 6 | paragraph=Fast library for parsing cstring into substrings, urlencode, unicode encode for Arduino 7 | category=Data Processing 8 | url=https://github.com/GyverLibs/GParser 9 | architectures=* -------------------------------------------------------------------------------- /src/GParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Простой и быстрый парсер строк в отдельные подстроки и числа для Arduino 3 | Документация: 4 | GitHub: https://github.com/GyverLibs/GParser 5 | Возможности: 6 | - Работает с указанным буфером (строкой), не создаёт свой 7 | - Разделяет строку на подстроки по указанному символу 8 | - Позволяет обращаться к подстрокам, переводить их в числа и сравнивать со строками 9 | - Доступ к подстрокам через [] 10 | - Может распарсить строку в массив int или byte 11 | 12 | AlexGyver, alex@alexgyver.ru 13 | https://alexgyver.ru/ 14 | MIT License 15 | 16 | Версии: 17 | v1.0 - релиз 18 | v1.1 - добавлены отдельные инструменты для парсинга 19 | v1.2 - добавлены ещё инструменты для парсинга 20 | v1.3 - добавлена возможность восстановить строку 21 | v1.3.1 - фикс warning 22 | v1.4 - добавил url и unicode кодирование 23 | */ 24 | 25 | #ifndef _GParser_h 26 | #define _GParser_h 27 | #include "utils/parseUtils.h" 28 | #include "utils/unicode.h" 29 | #include "utils/url.h" 30 | 31 | class GParser { 32 | public: 33 | // передать char array строку, можно указать символ разделитель 34 | GParser(char* data, char newDiv = ',') { 35 | buf = data; 36 | div = newDiv; 37 | } 38 | ~GParser() { 39 | clear(); 40 | } 41 | 42 | // указать символ разделитель 43 | void setDiv(char newDiv) { 44 | div = newDiv; 45 | } 46 | 47 | // освободить буфер 48 | void clear() { 49 | if (str) delete[] str; 50 | str = nullptr; 51 | } 52 | 53 | // количество разделённых данных в пакете 54 | int amount() { 55 | if (!buf) return 0; 56 | int count = 1; 57 | char* p = buf; 58 | while (*p) { 59 | if (*p++ == div) count++; // подсчёт разделителей 60 | } 61 | return count; 62 | } 63 | 64 | // разделить строку на подстроки 65 | int split() { 66 | len = amount(); // количество данных 67 | clear(); // освобождаем буфер 68 | str = new char*[len]; // создаём буфер 69 | if (!str) return 0; // ошибка аллокации 70 | str[0] = buf; // строка 0 71 | int i = 0, j = 0; // счётчики 72 | while (buf[i]) { // пока не NULL 73 | if (buf[i] == div) { // если разделитель 74 | buf[i] = '\0'; // меняем на NULL 75 | str[++j] = buf + i + 1; // запоминаем начало строки 76 | } 77 | i++; 78 | } 79 | return len; 80 | } 81 | 82 | // восстановить строку (вернуть разделители) 83 | void restore() { 84 | for (int i = 0; i < len - 1; i++) str[i][strlen(str[i])] = div; 85 | } 86 | 87 | // получить инт из выбранной подстроки 88 | int32_t getInt(int num) { 89 | return atol(str[num]); 90 | } 91 | 92 | // получить float из выбранной подстроки 93 | float getFloat(int num) { 94 | return atof(str[num]); 95 | } 96 | 97 | // сравнить подстроку с другой строкой 98 | bool equals(int num, const char* comp) { 99 | return !strcmp(str[num], comp); 100 | } 101 | 102 | // распарсить на лонги 103 | int parseLongs(long* data) { 104 | if (!buf) return 0; 105 | int count = 0; 106 | char* offset = buf; 107 | while (true) { 108 | data[count++] = atol(offset); 109 | offset = strchr(offset, div); 110 | if (offset) offset++; 111 | else break; 112 | } 113 | return count; 114 | } 115 | 116 | // распарсить на инты 117 | int parseInts(int* data) { 118 | if (!buf) return 0; 119 | int count = 0; 120 | char* offset = buf; 121 | while (true) { 122 | data[count++] = atol(offset); 123 | offset = strchr(offset, div); 124 | if (offset) offset++; 125 | else break; 126 | } 127 | return count; 128 | } 129 | 130 | // распарсить на байты 131 | int parseBytes(uint8_t* data) { 132 | if (!buf) return 0; 133 | int count = 0; 134 | char* offset = buf; 135 | while (true) { 136 | data[count++] = atoi(offset); 137 | offset = strchr(offset, div); 138 | if (offset) offset++; 139 | else break; 140 | } 141 | return count; 142 | } 143 | 144 | char* buf = nullptr; 145 | char** str = nullptr; 146 | 147 | char* operator[](uint16_t idx) { 148 | return str[idx]; 149 | } 150 | 151 | private: 152 | char div; 153 | int len; 154 | }; 155 | 156 | #endif -------------------------------------------------------------------------------- /src/utils/parseUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "parseUtils.h" 2 | 3 | // количество подстрок в списке list с разделителем div 4 | uint8_t GP_listSize(char* list, char div) { 5 | uint16_t i = 0, count = 0; 6 | while (list[i]) if (list[i++] == div) count++; 7 | return ++count; 8 | } 9 | 10 | // разделить список list с разделителем div на подстроки 11 | char* GP_splitList(char* list, char div) { 12 | static uint8_t prev, end; 13 | if (list == NULL) prev = end = 0; 14 | else { 15 | if (prev) *(list + prev - 1) = div; 16 | char* cur = strchr(list + prev, div); 17 | if (cur) { 18 | *cur = '\0'; 19 | uint8_t b = prev; 20 | prev = cur - list + 1; 21 | return list + b; 22 | } else if (!end) { 23 | end = 1; 24 | return list + prev; 25 | } 26 | } 27 | return NULL; 28 | } 29 | 30 | // получить номер, под которым name входит в list с разделителем div 31 | int8_t GP_inList(char* name, char* list, char div) { 32 | char* str = list; 33 | int8_t count = 0, pos = -1; 34 | GP_splitList(NULL); 35 | while ((str = GP_splitList(list, div)) != NULL) { 36 | if (!strcmp(str, name)) pos = count; 37 | count++; 38 | } 39 | return pos; 40 | } 41 | 42 | // преобразовать int в строку 43 | // DEC - 46, HEX/BIN - 17 (ltoa: BIN - 480, HEX - 125, DEC - 150) 44 | void GP_numToChar(int32_t n, char* buf, uint8_t base) { 45 | uint8_t l = 2; 46 | if (base != DEC) { 47 | int32_t nn = n; 48 | uint8_t b = (base == HEX) ? 4 : 1; 49 | while (nn >>= b) l++; 50 | char *str = &buf[l]; 51 | *--str = '\0'; 52 | do { 53 | char c = n & (base - 1); 54 | n >>= b; 55 | *--str = (c < 10) ? (c + '0') : (c + 'A' - 10); 56 | } while(n); 57 | } else { 58 | uint8_t s = 0; 59 | if (n < 0) n = -n, s = 1; 60 | int32_t nn = n; 61 | while (nn /= base) l++; 62 | char *str = &buf[l + s]; 63 | *--str = '\0'; 64 | do { 65 | _GP_div10 res(n); 66 | n = res.quot; 67 | *--str = (res.rem < 10) ? (res.rem + '0') : (res.rem + 'A' - 10); 68 | } while(n); 69 | if (s) *--str = '-'; 70 | } 71 | } 72 | 73 | // преобразовать float в строку 74 | void GP_floatToChar(double f, char *buf, uint8_t decimals) { 75 | dtostrf(f, decimals + 2, decimals, buf); 76 | } 77 | 78 | // преобразовать строку в число 79 | int32_t GP_charToNum(char* buf, uint8_t base) { 80 | if (base == DEC) return atol(buf); 81 | else return strtol(buf, NULL, base); 82 | } 83 | 84 | // преобразовать строку в float 85 | double GP_charToFloat(char* buf) { 86 | return atof(buf); 87 | } 88 | 89 | // получить число под индексом idx в списке list с разделителем div 90 | int GP_numFromList(char* list, int idx, char div) { 91 | uint8_t count = 0; 92 | char* p = list; 93 | while (1) { 94 | if (count++ == idx) return atoi(p); 95 | p = strchr(p, div); 96 | if (!p++) break; 97 | } 98 | return 0; 99 | } 100 | 101 | // переписать список list с разделителем div в массив чисел data размером size 102 | uint8_t GP_listToNum(char* list, int* data, uint8_t size, char div) { 103 | uint8_t count = 0; 104 | char* offset = list; 105 | while (1) { 106 | if (count >= size) break; 107 | data[count++] = atoi(offset); 108 | offset = strchr(offset, div); 109 | if (!offset++) break; 110 | } 111 | return count; 112 | } 113 | 114 | // преобразовать текстовый цвет (0x, #) в число 115 | uint32_t GP_decodeColor(char* hex) { 116 | uint32_t val = 0; 117 | uint8_t i = (hex[0] == '#') ? 1 : ((hex[1] == 'x') ? 2 : 0); 118 | for (; i < strlen(hex); i++) { 119 | val <<= 4; 120 | uint8_t d = hex[i]; 121 | d -= (d <= '9') ? 48 : ((d <= 'F') ? 55 : 87); 122 | val |= d; 123 | } 124 | return val; 125 | } 126 | -------------------------------------------------------------------------------- /src/utils/parseUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // количество подстрок в списке list с разделителем div 5 | uint8_t GP_listSize(char* list, char div = ','); 6 | 7 | // разделить список list с разделителем div на подстроки (см. пример) 8 | char* GP_splitList(char* list, char div = ','); 9 | 10 | // получить номер, под которым name входит в list с разделителем div. -1 если не входит 11 | int8_t GP_inList(char* name, char* list, char div = ','); 12 | 13 | // преобразовать int в строку 14 | void GP_numToChar(int32_t n, char* buf, uint8_t base); 15 | 16 | // преобразовать float в строку 17 | void GP_floatToChar(double f, char *buf, uint8_t decimals); 18 | 19 | // преобразовать строку в число 20 | int32_t GP_charToNum(char* buf, uint8_t base); 21 | 22 | // преобразовать строку в float 23 | double GP_charToFloat(char* buf); 24 | 25 | // получить число под индексом idx в списке list с разделителем div 26 | int GP_numFromList(char* list, int idx, char div = ','); 27 | 28 | // переписать список list с разделителем div в массив чисел data размером size 29 | uint8_t GP_listToNum(char* list, int* data, uint8_t size, char div = ','); 30 | 31 | // преобразовать текстовый цвет (0x, #) в число 32 | uint32_t GP_decodeColor(char* hex); 33 | 34 | 35 | // http://we.easyelectronics.ru/Soft/preobrazuem-v-stroku-chast-1-celye-chisla.html 36 | struct _GP_div10 { 37 | _GP_div10(uint32_t n) { 38 | quot = n >> 1; 39 | quot += quot >> 1; 40 | quot += quot >> 4; 41 | quot += quot >> 8; 42 | quot += quot >> 16; 43 | uint32_t qq = quot; 44 | quot >>= 3; 45 | rem = uint8_t(n - ((quot << 1) + (qq & ~7ul))); 46 | if (rem > 9) rem -= 10, quot++; 47 | } 48 | uint32_t quot; 49 | uint8_t rem; 50 | }; -------------------------------------------------------------------------------- /src/utils/unicode.cpp: -------------------------------------------------------------------------------- 1 | #include "unicode.h" 2 | char* GP_uniencode(int32_t c, char* s) { 3 | if (c < 0x80) { 4 | s[0] = (c & 0x7F) | 0x00; 5 | s[1] = 0; 6 | } else if (c < 0x0800) { 7 | s[0] = (c >> 6 & 0x1F) | 0xC0; 8 | s[1] = (c & 0x3F) | 0x80; 9 | s[2] = 0; 10 | } else if (c < 0x010000) { 11 | s[0] = (c >> 12 & 0x0F) | 0xE0; 12 | s[1] = (c >> 6 & 0x3F) | 0x80; 13 | s[2] = (c & 0x3F) | 0x80; 14 | s[3] = 0; 15 | } else if (c < 0x110000) { 16 | s[0] = (c >> 18 & 0x07) | 0xF0; 17 | s[1] = (c >> 12 & 0x3F) | 0x80; 18 | s[2] = (c >> 6 & 0x3F) | 0x80; 19 | s[3] = (c & 0x3F) | 0x80; 20 | s[4] = 0; 21 | } 22 | return s; 23 | } 24 | 25 | String GP_uniencode(uint16_t c) { 26 | char str[5]; 27 | return String(GP_uniencode(c, str)); 28 | } 29 | 30 | uint16_t GP_unistrlen(char* data) { 31 | uint16_t i = 0, count = 0; 32 | while (data[i]) { 33 | if ((data[i] & 0xc0) != 0x80) count++; 34 | i++; 35 | } 36 | return count; 37 | } -------------------------------------------------------------------------------- /src/utils/unicode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | char* GP_uniencode(int32_t c, char* s); 4 | String GP_uniencode(uint16_t c); 5 | uint16_t GP_unistrlen(char* data); -------------------------------------------------------------------------------- /src/utils/url.cpp: -------------------------------------------------------------------------------- 1 | #include "url.h" 2 | void GP_urlencode(const String& s, String& dest) { 3 | dest.reserve(s.length()); 4 | char c; 5 | for (uint16_t i = 0; i < s.length(); i++) { 6 | c = s[i]; 7 | if (c == ' ') dest += '+'; 8 | else if (!( 9 | (c >= '0' && c <= '9') || 10 | (c >= 'a' && c <= 'z') || 11 | (c >= 'A' && c <= 'Z') || 12 | c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || 13 | c == '*' || c == '\'' || c == '(' || c == ')' 14 | )) { 15 | dest += '%'; 16 | dest += (char)((c >> 4) + (((c >> 4) > 9) ? 55 : 48)); 17 | dest += (char)((c & 0xF) + (((c & 0xF) > 9) ? 55 : 48)); 18 | } else dest += c; 19 | } 20 | } 21 | 22 | String GP_urlencode(const String& s) { 23 | String dest; 24 | GP_urlencode(s, dest); 25 | return dest; 26 | } 27 | 28 | void GP_urldecode(const String& s, String& dest) { 29 | dest.reserve(s.length()); 30 | char c; 31 | for (uint16_t i = 0; i < s.length(); i++) { 32 | c = s[i]; 33 | if (c != '%') dest += (c == '+') ? ' ' : c; 34 | else { 35 | c = s[++i]; 36 | uint8_t v1 = c - ((c <= '9') ? 48 : ((c <= 'F') ? 55 : 87)); 37 | c = s[++i]; 38 | uint8_t v2 = c - ((c <= '9') ? 48 : ((c <= 'F') ? 55 : 87)); 39 | dest += char(v2 | (v1 << 4)); 40 | } 41 | } 42 | } 43 | 44 | String GP_urldecode(const String& s) { 45 | String dest; 46 | GP_urldecode(s, dest); 47 | return dest; 48 | } -------------------------------------------------------------------------------- /src/utils/url.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | void GP_urlencode(const String& s, String& dest); 4 | String GP_urlencode(const String& s); 5 | void GP_urldecode(const String& s, String& dest); 6 | String GP_urldecode(const String& s); --------------------------------------------------------------------------------