interrupt 0 3 декабря, 2015 Опубликовано 3 декабря, 2015 · Жалоба Такая задача. Контроллер принимает по UART некоторые данные в виде строк разной длины и содержания. Т.е. обычные текстовые строки. В этих строках может содержаться команда для контроллера, например: Switсh on out 7, input 1 disable, Led 11 on. Строки хранятся до разбора в массиве. Размер массива ограничен, а частота поступления новых строк не нормируется. Поэтому нужно быстро разобрать строку, вычленить из нее ключевые слова и передать соответствующие команды основной программе. Задача усложняется тем, что таких слов будет около 100, кроме того, в будущем их кол-во предполагается увеличить. Как реализуется обычно такая задача? Ничего умнее, как последовательный поиск каждого слова в строке придумать не могу. Но это очень долго получается. Например, сначала придется пролистать весь массив в поисках "Led", потом опять весь массив в поисках "input" и т.д. А хочется читать строку 1 раз, по пути находя все ключевые слова. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Александр77 1 3 декабря, 2015 Опубликовано 3 декабря, 2015 · Жалоба Если есть возможность повлиять на формирование самих команд, то можно перед "значимой" частью передавать преамбулу (уникальный символ или группа символов). Найдя преамбулу в строке можно взвести флаг о том, что дальше идет/идут команды. Окончание поля команд тоже можно обособить для того, чтобы декодировку и поиск. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
interrupt 0 3 декабря, 2015 Опубликовано 3 декабря, 2015 · Жалоба Да в общем-то все данные получаются значимыми. Просто не известно, какая команда будет первой, какая последней, сколько команд будет в строке и каких именно. Т.е. строка может выглядеть так: Switch on out 1, led 7 off. А может так: led 8 on, timer1 stop, Switch on out6, led 9 off Как пример. Есть GSM-модуль, управляемый через терминал. Допустим, я ввожу команду AT+CGSN\r\n Что происходит дальше? Как контроллер обрабатывает эту строку и находит соответствие этой записи конкретной команде? Вот мне нужно реализовать примерно то же самое. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
CrimsonPig 0 3 декабря, 2015 Опубликовано 3 декабря, 2015 (изменено) · Жалоба Да в общем-то все данные получаются значимыми. Просто не известно, какая команда будет первой, какая последней, сколько команд будет в строке и каких именно. Т.е. строка может выглядеть так: Switch on out 1, led 7 off. led 8 on, timer1 stop, Switch on out6, led 9 off Ну, для начала надо взять большой листок бумаги и разрисовать машину состояний, которая будет обрабатывать ваши ключевые слова. Например, команда "Switch on out 1" правильная, а "Switch 1 on out" неправильная, я надеюсь. :) То есть при приеме токена "switch" следующим токеном должен быть "on" или "off" итп. Если вы начнете кодить не имея полного формального описания автомата разбора, ничего не получится. После того, как разбор кое-как заработеет, можно уже наворачивать фичи для улучшения производительности, типа считать хэши тогенов из входного потока, и искать их в хэш-таблице известных ключевых слов. Если повезет, можно истпользовать perfect hash. А вот потом начнется самое интересное :) Тестирование :) А то в ваш парзер придет строка "led -1 fuck off" и он зависнет в бесконечном цикле :) Изменено 3 декабря, 2015 пользователем CrimsonPig Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
interrupt 0 3 декабря, 2015 Опубликовано 3 декабря, 2015 · Жалоба Ну, для начала надо взять большой листок бумаги и разрисовать машину состояний, которая будет обрабатывать ваши ключевые слова. Например, команда "Switch on out 1" правильная, а "Switch 1 on out" неправильная, я надеюсь. :) То есть при приеме токена "switch" следующим токеном должен быть "on" или "off" итп. Если вы начнете кодить не имея полного формального описания автомата разбора, ничего не получится. После того, как разбор кое-как заработеет, можно уже наворачивать фичи для улучшения производительности, типа считать хэши тогенов из входного потока, и искать их в хэш-таблице известных ключевых слов. Если повезет, можно истпользовать perfect hash. А вот потом начнется самое интересное :) Тестирование :) А то в ваш парзер придет строка "led -1 fuck off" и он зависнет в бесконечном цикле :) Ну примитивный разбор работает. Т.е. я просматриваю строку в поисках "Switch". Далее смотрю уже "off" или "on", далее объект "out", потом номер. Далее приходится снова просматривать всю строку в поисках "timer" -> номер таймера -> команда. Необходимо оптимизировать именно начальный поиск (а оп аналогии и разветвления так же). Ну например, просматриваю строку. Первая буква "S" - таких команд 10. Вторая "w" - таких команд 5. Третья "i" - таких команд 1. Проверяю, действительно ли это она ну и смотрю ее параметры. Далее нахожу разделитель, например ",". После нее 1-я буква "L" - 20 команд, 2-я "e" - 2 команды, ну и т.п. Т.е. обработка всей строки за 1 проход. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 8 3 декабря, 2015 Опубликовано 3 декабря, 2015 (изменено) · Жалоба Можно составить статический связный список соответствия вида 'символ' -> 'команда1', 'команда2', ... 'командаN', в который внести команды, в которых этот символ встречается, и упорядочить его по частоте употребления символа в командах, начиная с наиболее популярного. Например, в вашем случае словарь команд состоит из 3 команд - switch,timer,led. Видим, что самые популярные символы в командах - это t, i и e (встречаются по 2 раза). Начнём с любого из них, например, t: 't' -> "timer", "", "", "switch", NULL 'e' -> "", "led", NULL Позиция команды в списке "по горизонтали" соответствует позиции искомого символа внутри команды. NULL заканчивает связный список. Тогда, чтобы вычленить и выполнить команду в пришедшей строке, в которой команд может быть несколько в любом порядке, необходимо организовать последовательный поиск символов, начиная с наиболее популярного и далее вниз по списку. Бежим по разбираемой строке с каждым символом из списка - если символ находится, то в этом месте начинаем уже перебирать команды, связанные с этим символом и сравнивать на совпадение. Совпало? Выполняем команду со всеми аргументами и идем дальше. Почему список начинается с наиболее популярных символов? Чтобы увеличить вероятность разбора всей строки без перебора всего списка. Для этого надо после распознания и выполнения каждой команды вычитать из длины строки количество распознанных символов, пока не останется ноль. Прошли весь список, а ноль не остался? Синтаксическая ошибка в строке. Изменено 3 декабря, 2015 пользователем gerber Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Такая задача. Контроллер принимает по UART некоторые данные в виде строк разной длины и содержания. Т.е. обычные текстовые строки. В этих строках может содержаться команда для контроллера, например: Switсh on out 7, input 1 disable, Led 11 on. У Вас как я понял строка-команда представляет из себя смесь команд (которые являются группой из латинских букв+цифр) разделённых знаками препинания и пробелами? Тогда разбиваете строку на лексемы (группы алфавитно-цифровых символов разделённых знаками препинания) за один проход по строке. Потом просто для каждой лексемы ищете её в массиве - есть-ли такая. Массив - это набор хешей (ну или просто CRC32) для всех возможных команд. Тогда для каждой лексемы достаточно одного прохода поиска по массиву 32-битных слов. Да и поиск лучше делать по ходу выделения лексем. Так проще контролировать правильность синтаксиса всей строки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Я бы задумался над постановкой задачи, ибо в ней противоречие. С одной стороны, ввод текста человеком, а с другой, жесткие рамки парсера. Сам делал что-то подобное, в результате не используется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Я бы задумался над постановкой задачи, ибо в ней противоречие. С одной стороны, ввод текста человеком, а с другой, жесткие рамки парсера. Если ввод человеком, то требования по скорости должны быть вообще никакие. А тут какие-то массивы на множество строк, непонятно зачем..... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
psL 0 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба вот проект. решает аналогичную задачу. может пригодится. lwshell.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
interrupt 0 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Ввод может быть как человеком, так и внешним устр-вом. Как пример я привел GSM-модуль: можно ручками через терминал писать ему команды, а можно выстреливать их из контроллера. При этом последовательность команд будет разной, кол-во в общем-то тоже (0xOD выступает в качестве разделителя и флага одновременно). C CRC32 интересно, тоже думал в этом направлении. Наверно, это наиболее быстрый вариант (считать CRC32 для первого слова, искать в массиве команд. Потом CRC второго слова - искать в массиве, и так, пока не наткнулся на подходящее. Разобрал команду - пошел дальше). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lmx2315 5 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Может упростить задачу? Писать примерно так : "~ включить_канал:1;" где "~" - стартовый байт "включить_канал" - команда ":" признак что потом идёт число ";" признак конца пачки команду собирать побайтно в массив и сравнивать через strcmp . IO("~ включить_канал:1;",19); io.txt Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
interrupt 0 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба вот проект. решает аналогичную задачу. может пригодится. Спасибо, пойду разбираться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Вам подойдет поиск по Регулярным Выражениям. Из всех ваших команд делается 1 регулярное выражение, из которого строится конечный автомат. Он (автомат) запускается на входной поток символов и выдает все совпадения за 1 проход над входной строкой (на лету) Если вас устроит готовый парсер можете посмотреть в сторону flex - он генерирует готовый автомат Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
interrupt 0 4 декабря, 2015 Опубликовано 4 декабря, 2015 · Жалоба Может упростить задачу? Писать примерно так : "~ включить_канал:1;" где "~" - стартовый байт "включить_канал" - команда ":" признак что потом идёт число ";" признак конца пачки команду собирать побайтно в массив и сравнивать через strcmp . IO("~ включить_канал:1;",19); Ну сейчас примерно так и делается. Сначала я ищу команду "включить" потом номер канала, потом разделитель. Просто самих команд достаточно много, приходится по много раз заниматься поиском возможной команды по всей строке. Сама команда состоит из 1 слова, номера канала, уровень сигнала и т.п. - это параметры, разбираемые после обнаружения команды. За пример спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться