Очередной парсинг строк. Нид хелп!
- Войдите на сайт для отправки комментариев
Пт, 12/02/2021 - 09:32
Всем привет!
Ай нид хелп.
У меня есть входящие команды такого типа:
1. [команда]:[номер]:[номер]
2. [команда]:[номер]:[номер]:[значение]
Мне необходимо их обрабатывать. Сейчас это всё собирается в строку, затем парсится, раскладывая нужные значения в нужные переменные руками. Меня этот вариант не устраивает.
Мне товарищ сказал что это можно делать быстрее с помощью регулярок типа (\w+):(\d+):(\d+):?(.*)
Дак, вот, я без понятия как этим пользоваться в дуино.
Если кто имел дело, поделитесь опытом, плиз.
вот пример команд:
start:1:1
speed:1:1:1234
time:60
Регулярки на AVR? Ну, так себе идея против простого парсинга по разделителям.
Вот, тоже, изучил либу подробнее. Она посимвольно перебирает и вообще отжирает много динамической памяти.
Подумываю создать структуру данных содержащую в себе разделитель ":" и несколько переменных, в которых будут храниться полученные данные. Вопрос - насколько это будет грамотно и оптимально для ОЗУ?
Разделитель не типовой, кстати. Причина: дальше это летит в нижний уровень устройства(на СТМ).
че там думать то, никакой либы не надо, заводите переменную шага/статуса и в зависимости от входящего символа или дальше ищите число или конец команды
вот еще нашел старый пример
че там думать то, никакой либы не надо, заводите переменную шага/статуса и в зависимости от входящего символа или дальше ищите число или конец команды
Благодарю!
https://github.com/nickgammon/Regexp
scanf() заюзать не получица?
вот пример команд:
ua3rkv?
вас не устраивает скорость парсинга при вашем варианте? или код длинный?
можно например так, время парсинга около 100 микросекунд
Или зависнет нафиг, если в 27ю строку вместо цифры буква прилетит :(
Число в этом случае просто запарсится нулём. из гугла про atoi:
Функция сначала отбрасывает символы пробелов до тех пор, пока не будет найден символ отличный от нуля. Затем, начиная с этого символа, функция принимает необязательный начальный знак плюс или минус. После чего, следует последовательность цифр, которая интерпретируется в числовое значение.
Строка может содержать другие символы после считанного целого числа, эти символы игнорируются и никак не влияют на поведение этой функции.
Да пожалуйста, символ пропустится и хрен с ним, вместо цифры 1234,запишется 234, а впрочем не важно, "хозяин-барин".
вот во что парсится такая строка , главное чтобы перед числом не было лишних символов , после можно, пробелы тоже можно
start: 675 da dfa : 4535 bla bla : 7894 ho ho
start
ну как бы если такие требования, можно КС какую нибудь вводить в протокол, если символ пропустится пакет вообще-то не валидный
вас не устраивает скорость парсинга при вашем варианте? или код длинный?
можно например так, время парсинга около 100 микросекунд
Всё куда тривиальнее - меня просто не устраивало то что было.
вас не устраивает скорость парсинга при вашем варианте? или код длинный?
можно например так, время парсинга около 100 микросекунд
как - то так по итогу и вышло. Только я одного понять не могу - все всегда парсят посимвольно. Вопрос зачем, если можно так IncomingDataBT = Serial3.readStringUntil('\n');?
как-то так в итоге
Только я одного понять не могу - все всегда парсят посимвольно. Вопрос зачем, если можно так IncomingDataBT = Serial3.readStringUntil('\n');?
вы удивитесь, но посимвольно быстрее
Я бы не сказал "быстрее", скорее "многозадачней".
И это тоже. А еще более гибко - разбираемая строка не обязательно должна иметь перевод в конце.
А при отсутствии "\n" в конце строки - будет еще и быстрее :))
как - то так по итогу и вышло. Только я одного понять не могу - все всегда парсят посимвольно. Вопрос зачем, если можно так IncomingDataBT = Serial3.readStringUntil('\n');?
А что будет , если в момент перевода строки данные потеряются ?
Нужно рассматривать работу системы не только в сферическом вакууме
Только я одного понять не могу - все всегда парсят посимвольно. Вопрос зачем, если можно так IncomingDataBT = Serial3.readStringUntil('\n');?
Потому что "так" - можно не всегда, а только для относительно коротких строк. Есть и другие причины. В общем, во всех отношениях парсить посимвольно - лучше.
Потомучто
как - то так по итогу и вышло. Только я одного понять не могу - все всегда парсят посимвольно. Вопрос зачем, если можно так IncomingDataBT = Serial3.readStringUntil('\n');?
А куда они потеряются? В дуине есть буфер, в которой складываются данные с уарта. Вы так или иначе берёте символы из буфера, а не на прямую из уарта.
-
Я скачивал её ещё ранее. Поковырял, посмотрел. Меня не устроила по двум причинам:
1.Слишком много жрёт для такого парсинга(Честно говоря я бы подумал несколько раз чтобы пихать такое в дуино).
2.Разбирает по факту так же посимвольно. Очень костыльно выходит.
Потомучто
Ну, два момента:
1. Я не использую луп вообще.
2. Если не пришел символ конца строки, значит канал данных не стабилен и использование такого канала без протоколов(например HDLC) рисковано.
Другими словами, если у Вас не пришел конец строки, который должен прийти, что в первом, что во втором случае является ошибкой в коммуникации устройств.
Что даёт посимвольный парсинг, если вы в любом случае не получаете нужного терминатора строки?
Кроме того, обратите внимание, что в посте речь идёт о посимвольном считывании из серийного порта с использованием не явного приведения типов.
Ваше "потомучто" не объяснило ничего.
Вот немного мат.части. Давайте рассмотрим вопрос, опираясь на офф документацию.
1. Задержку выполнения кода вызванную отсутствием терминируещего символа можно регулировать.
2. Сама по себе функция посимвольно складывает данные из буфера в строку, т.е. в массив символов.
Я вижу это так:
Выполняем проверку при парсинге в два уровня.
Первый - проверяем целостность строки по терминирующему символу
Второй - уже во время парсинга смотрим наличие разделителей.
Как по мне, куда удобнее работать со строкой. Другое дело, что в моём методе всегда выделяется память для входящей строки, когда при посимвольном переборе можно этого избежать, но речь идёт о крохах.
Вот немного мат.части.
Простите, можно уточнить Вашу цель при создании этой темы?
В заголовке Вы написали "Нид хелп!", а на деле занимаетесь тем, что учите "неправильно парсить строки" тех, кто пытается Вам помочь.
Если Вы лучше знаете как надо делать и разбираетесь в матчасти, так и делайте на здоровье. Какого ещё хелпа Вам надо?
Да, я, собственно, уже получил помощь. Просто, обсуждение продолжается. А мне любопытно.
На деле я не учу никого парсить строки. Идет рассуждение на тему того как лучше это делать.
Мне говорят - "вот так", я спрашиваю "почему". Далее привожу довод почему меня это смущает и предлагаю всем вместе разобраться в теме.
Я человек дотошный и принять "потому что" на веру мне сложно, как и сложно принять "потому что так все делают". Я уверен, что тут есть спецы с огромным опытом в программировании дуино, которые смогут мне объяснить, если захотят конечно.
Если у Вас такого желания нет, то просто пройдите мимо.
Да, Вы просто указываете, что мне делать
А почему собственно я должен проходить мимо, если, как Вы изволили выразиться,
Я задал Вам вопрос, а Вы меня лесом ... Вам одному позволительно задавать вопросы? Или как?
По моему тут идет смешение понятий "получение данных" и "парсинг данных."
Получать часто лучше (в плане возможной "многозадачности") посимвольно. А собственно парсинг - в зависимости от задачи, и тут (по моему) нет универсального совета.
Да, Вы просто указываете, что мне делать
А почему собственно я должен проходить мимо, если, как Вы изволили выразиться,
Я задал Вам вопрос, а Вы меня лесом ... Вам одному позволительно задавать вопросы? Или как?
Тут проблема в Вашем восприятии.
А ещё скиньте пожалуйста цитатой, где я лично Вам указываю что делать. Так сказать "пруфы где")
Думаю Вы правы, учитывая, что бывают "сырые" данные. А что касается смешения - тут невероятно тонкая грань.
2. Сама по себе функция посимвольно складывает данные из буфера в строку, т.е. в массив символов.
ну вот, насчета приема вы уже согласились - прием в любом случае выполняется посимвольно.
Остается парсинг. Если не упираться в пустой спор, а немного подумать - внутри себя все функции. которые якобы "работают со строкой" - на самом деле разбирают ее посимвольно . Просто это скрыто от вас "под капотом".
Так что спор-то в общем ни о чем. А ваше упорное противопоставление "посимвольного" и "строчного" парсинга просто убеждает, что вы беретесь учить других, не разобравшись прежде в базовых понятиях сами.
Вот немного мат.части. Давайте рассмотрим вопрос, опираясь на офф документацию.
1. Задержку выполнения кода вызванную отсутствием терминируещего символа можно регулировать.
2. Сама по себе функция посимвольно складывает данные из буфера в строку, т.е. в массив символов.
Я вижу это так:
Выполняем проверку при парсинге в два уровня.
Первый - проверяем целостность строки по терминирующему символу
Второй - уже во время парсинга смотрим наличие разделителей.
Как по мне, куда удобнее работать со строкой. Другое дело, что в моём методе всегда выделяется память для входящей строки, когда при посимвольном переборе можно этого избежать, но речь идёт о крохах.
По утрам я всегда добрый, пока еще трезвый ;)). Поэтому поясню, но ровно до первого спора. Ни с Евгением, ни со мной ни с кем из старых участников у тебя еще "орган не отрос" спорить. Пока на таких условиях.
Отвечать буду по ходу цитаты, без нумерования. Цитата - твоя, разберешься. Это ж тебе надо, так-то, по-большому? Речь будет про 8-ми битные AVR контроллеры. На ESP - делай как тебе нравится, там и частота и память совсем в иных количествах
Если что-то будет нуждаться в дополнительных пояснениях - ссылайся уже на мой номер.
1. Использовать readStringUntil() - можно очень хорошо понимая где и как ты это делаешь. Она ждет терминатора в течении заданного таймаута, по умолчанию - 1 сек. На это время работа контроллера - остановлена, кроме прерываний. Здесь понял?
2. Регулировать можно, если она маленькая - то вообще не имеет смысла. Строка не пришла, что ты делаешь? Она-то пришла, просто ты неудачно попал вне таймаута.
3. Сперва ты принимаешь строку, реально - по символу, или, вместо приема по символу, провисишь в ожидании, пока строка придет со скоростью... хорошо, если 115200, а если 9600? ;)) А потом посимвольно парсишь. Почему "посимвольно"? - потому, что у процессора одно ядро и параллелить он не умеет, как бы ты себя не обманывал - обработка идет посимвольно. Другое дело, что на больших компьютерах или контроллерах есть стандартные библиотеки, которые спрячут от тебя обработку и тебе, как программисту, станет легче писать код.
4. как и написано выше - ты сам признаешься, что тебе "удобнее" работать со строкой. Не дай Б..г, еще и тип String в AVR 8-и битный потянешь! Это понятно - приход в контроллеры, или, как говорят программисты "в ембеддинг" из, прости Господи, веба и чего-то подобного! ;)) Да, я немного глумлюсь, прости. Ембеддеры - в неком смысле "элита" программирования, а веб-кодеры - на уровне технического персонала. Не нужно с этим спорить, это не истина в последней инстанции, а распространенное мнение. Просто имей ввиду, как смотрят тут на "веб-кодеров".
5. Ладно, это было отвлечение в сторону. Теперь к делу. Еще раз: представь себе маленький контроллер и прием команды по сериалу со скоростью 9600. Символ целиком придет за 1 мс. Это 16000 тактов процессора. И ты все это время будешь просто курить бамбук? А зачем? Если потом ты все равно будешь парсить строку. И, если не применять библиотеки типа той, что указал Женя, то парсить посимвольно. Ну так и сделай за эти 16000 тактов что-то полезное, в частности порцию парсинга. И не забываем, что оперативки у нас 2К. Так что лишний буфер на строку - это не "крохи".
6. Вообще, правильный стиль в парадигме "сетап-луп", используемой в Ардуино, это принять ОДИН символ в проходе лупа и сделать необходимый анализ его для парсинга. Таким образом нет простоя контроллера и выполняются иные полезные действия, для которых прибор проектируется - управление внешними устройствами и сбор данных с датчиков. Многие новички делают ту самую ошибку, к которой ты стремишься ;)) - принять в одном проходе лупа больше одного символа? Подумай - зачем? Проход лупа - как автобус - всегда будет следующий. ;))
Вообще, при обучении, правильный подход - копирование лучших техник, а потом уже, с опытом придет понимание - где и как можно "срезать".
Когда-то в юности меня учил сваривать оптоволокно старый дядька, советской выучки, еще на сварочнике без экрана, со стерео-микроскопом. Он говорил: "Делай хорошо, а плохо - оно само получится!". Хорошая мысль, нет?
Мне не понятно в чём заключается моё учение кого либо? Что за голословные фразы?
Подкрепите, пожалуйста, их цитатами.
Если такие найдутся, я сменю форму подачи информации в массы. Я искренне не понимаю этих обвинений.
Если такие найдутся, я сменю форму подачи информации в массы. Я искренне не понимаю этих обвинений.
Положим не "учите", а беретесь "подавать информацию в массы" - не разобравшись сами, что же эта информация значит.
Вы извините, но я не статью на вики пишу.
Вы извините, но я не статью на вики пишу.
по-моему, уже начались "виляния хвостом".
Все эти обсуждения кто кого учит, как надо подавать информацию - не более чем попытки уйти от обсуждения сути "построчного парсинга", поскольку ТС начинает понимать, что в сути вопроса он явно сел в лужу...
Спасибо тебе ВечноМолодойИПокаЕщёТрезвый!
Вот, как раз с вебом-то я и не знаком) Оттуда и вопрос появился про регулярки(слышал звон да не знаю... Вот и пошёл спрашивать у знающих).
Это не "виляния хвостов", я цитаты не увидел. Видимо нечего было скидывать, потому "объезд" темы.
А ещё скиньте пожалуйста цитатой, где я лично Вам указываю что делать. Так сказать "пруфы где")
Или вот эта фраза в посте, обращённом лично ко мне, не есть указание, что мне делать?
Мне не понятно в чём заключается моё учение кого либо? Что за голословные фразы?
Подкрепите, пожалуйста, их цитатами.
Если такие найдутся, я сменю форму подачи информации в массы. Я искренне не понимаю этих обвинений.
Цитата "вот немного мат.части". "давайте рассмотрим" и подобное.
Родное сердце, выше уже в иных фразах спрашивали тебя: Ты пришел узнать что-то или подискутировать от избытка времени? ;))
Дискутировать - пока не надо, честно и без обид - не надо. Может быть потом, когда немного уровень поднимешь.
Спросить - тебе объяснили, и я - в том числе, ПОЧЕМУ в контроллере правильно парсить по мере прихода символов из сериала. Если ты, обладая пытливостью ума, хочешь что-то уточнить - велком! Я поясню.
Если ты настаиваешь на том, чтобы сперва принять всю строку, а потом парсить - пиши так, только доказывать эту точку зрения не надо, она - неправильная. И тебе уже объяснили - почему. Тогда следует признать, что "отношения не сложились" и не стоит продолжать бессмысленное общение.... на срач скатится.
Если ты настаиваешь на том, чтобы сперва принять всю строку, а потом парсить - пиши так, только доказывать эту точку зрения не надо, она - неправильная.
Чойта? Я всегда сначала принимаю всю строку, дабы удебицца, что она не битая, а потом отдаю на парсинг. Строка в текстовом виде, в формате:
L#cc...cc#CRC
L - длина строки унутре #..#, 1-3 символа
# - маркер начала и конца значимых данных
ccc...ccc - сопсно, значимые данные
СRC - Контрольная сумма crc16 1-5 символов
Благодарю за объяснение, всех принимавших участие и проявивших благоразумие не отвлекаться на мелочи.
Евгений П, серьезно? расслабьтесь(советую, не указываю), словно тем больше нет для обсуждений, кроме как за слова цепляться. Если так трогает моя ошибка в подаче текста Вас и кого то ещё, извиняюсь. Нет, я не виляю(вдруг кому показалось), свожу бессмысленные споры на нет.
Есть косяк - задел человека(может и не одного), извинился.
А что касается созданной мной темы, то я, в общем-то, узнал всё что было интересно и даже более.
Считаю тему закрытой.
Если ты настаиваешь на том, чтобы сперва принять всю строку, а потом парсить - пиши так, только доказывать эту точку зрения не надо, она - неправильная.
Чойта? Я всегда сначала принимаю всю строку, дабы удебицца, что она не битая, а потом отдаю на парсинг. Строка в текстовом виде, в формате:
L#cc...cc#CRC
L - длина строки унутре #..#, 1-3 символа
# - маркер начала и конца значимых данных
ccc...ccc - сопсно, значимые данные
СRC - Контрольная сумма crc16 1-5 символов
Не уверен, что даже в твоем исполнении это разумно, но твой уровень знаний позволяет делать так, как тебе хочется. Что нельзя сказать о ТС. Ты же не висишь в readStringUntil() ? Воот! Об этом и речь!
Ну вот у меня про что-то подобное.
Попробую перечитать всё третий раз, но за два раза так и не понял. (Вы уж будьте благосклонны Ембенды :))
У меня данные приходят из блютуса.
Так понимаю они приходят посимвольно. Проблема в том, что надо отследить, что они все пришли. Для этого все char -ы посимвольно заталкиваем в строку, "отлавливаем" последний какой-то там нулевой символ типа '\n'. И потом парсим строку (по парсингу я задам отдельный вопрос) по какому то символу, например по ':' и расталкиваем по другим массивам и строкам.
Это если без библиотек.
Ну ладно. А не может в таком случае прийти не все символы, но в середине.
Т.е. должно прийти например 'H' 'e' 'l' 'l' 'o' '\n', а придёт 'H' 'e' 'l' 'o' '\n'. Вроде и есть конец символа строки, но строка не та, какая нужна. Может есть для таких случаев какая-нибудь "Хеш сумма"?
И 2 вариант, прямо с ходу считывать символы, расталкивая (дойдя до ':') по массивам и строкам, а если в конце пришёл '\n' т.е. bool OK = true и работать дальше с новыми массивами и строками?
Какой вариант использовать лучше 1-й или 2-й?
Я хочу делать по 1-му, но кажется, что и 1-й вариант не исключает ошибки