Соответствие темы подписки MQTT


10

Фон

MQTT (Телеметрический транспорт сообщений) является стандартным протоколом обмена сообщениями на основе публикации и подписки ( Википедия ).

Каждое сообщение имеет тему, например следующие примеры:

  • myhome/groundfloor/livingroom/temperature
  • USA/California/San Francisco/Silicon Valley
  • 5ff4a2ce-e485-40f4-826c-b1a5d81be9b6/status
  • Germany/Bavaria/car/2382340923453/latitude

Клиенты MQTT могут подписываться на темы сообщений, используя подстановочные знаки:

  • Единый уровень: +
  • Все уровни вперед: #

Например, подписка myhome/groundfloor/+/temperatureвыдаст следующие результаты (несоответствия, выделенные жирным шрифтом ):

✅ мой дом / первый этаж / гостиная / температура
✅ мой дом / первый этаж / кухня / температура
❌ мой дом / первый этаж / гостиная / яркость
❌ мой дом / первый этаж / гостиная / температура
гараж / первый этаж / холодильник / температура

Принимая во внимание, что подписка +/groundfloor/#дала бы эти результаты:

✅ мой дом / первый этаж / гостиная / температура
✅ мой дом / первый этаж / кухня / яркость
✅ гараж / первый этаж / холодильник / температура / более / специфический / поля
❌ мой дом / первый этаж / гостиная / температура
❌ мой дом / подвал / угол / температура

Больше информации здесь .

Задание

Реализуйте функцию / программу, принимающую две строки и возвращающую логическое значение. Первая строка - тема темы, вторая - тема критерия. В разделе критериев используется синтаксис подписки, описанный выше. Функция правдива, когда субъект соответствует критериям.

Правила для этой задачи:

  • Темы ASCII
  • Поля критериев, кроме #подстановочных знаков, отсутствуют
  • Подстановочные знаки не отображаются в темах
  • Количество тематических полей> = количество полей критериев
  • Здесь нет 0-символьных полей, ни начальных, ни хвостовых косых черт

Контрольные примеры

критерии1 = "мой дом / земляной пол / + / температура"
критерии2 = "+ / земляной пол / #"

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("мой дом / первый этаж / гостиная / температура", критерии1 ) => true
(«мой дом / первый этаж / кухня / температура», критерии1) => правда
(«мой дом / первый этаж / гостиная / яркость», критерии1) => false
(«мой дом / первый этаж / гостиная / температура», критерии1) = > false
("гараж / первый этаж / холодильник / температура", критерии 1) => false
("мой дом / первый этаж / гостиная / температура", критерии 2) => true
("мой дом / первый этаж / кухня / яркость", критерии 2) => правда
(»гараж / цокольный этаж / холодильник / температура / более / специфические / поля ", критерии 2) => верно
(" мой дом / первый этаж / гостиная / температура ", критерии 2) => false
("myhome / подвал / угол / температура", критерий 2) => false
("music / kei $ ha / latest", "+ / kei $ ha / +") => true


@HyperNeutrino, это хороший вопрос. Я на заборе. Субъект a/b/cне соответствует критериям a/b, поэтому я склонен сказать нет .
Патрик

4
/, + И # гарантированно никогда не появятся в разделах темы?
Джонатан Аллан

Я вижу в блоге ссылку «Кроме того, только косая черта является допустимой темой», но нет упоминаний о + и #, так что я думаю, что эти два могут быть.
Джонатан Аллан

1
@JonathanAllan От docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : Символы подстановки могут использоваться в фильтрах тем , но НЕ ДОЛЖНЫ использоваться в имени темы
Ник Кеннеди

2
@NickKennedy - хорошо копать, но нам действительно не нужно.
Джонатан Аллан

Ответы:


3

Желе , 20 байт

ṣ€”/ZṖF”#eƊ¿œiÐḟ”+ZE

Монадическая ссылка, принимающая список списков символов [topic, pattern], который возвращается 1либо 0для совпадения, либо для несоответствия соответственно.

Попробуйте онлайн! Или посмотрите тестовый набор .

Как?

ṣ€”/ZṖF”#eƊ¿œiÐḟ”+ZE - Link: list of lists of characters, [topic, pattern]
 €                   - for each:
ṣ                    -   split at occurrences of:
  ”/                 -     '/' character
    Z                - transpose (any excess of topic is kept)
           ¿         - while...
          Ɗ          - ...condition: last three links as a monad:
       ”#            -   '#' character
         e           -   exists in:
      F              -     flatten
     Ṗ               - ...do: pop the tail off
              Ðḟ     - filter discard those for which:
            œi       -   first multi-dimensional index of: ([] if not found, which is falsey)
                ”+   -     '+' character
                  Z  - transpose
                   E - all equal?

2

Рубин , 65 байт

Регулярное решение. Я добавил, что Regex.escapeв случае, если имя критерия окажется чем-то похожим com.java/string[]/\nили глупым, в котором будут кусочки регулярных выражений.

->s,c{s=~/^#{Regexp.escape(c).sub('\#','.*').gsub'\+','[^/]*'}$/}

Попробуйте онлайн!

Решение без регулярных выражений, 77 байт

Использует хорошую простую технику разделения, почтового индекса и соответствия. Сначала я разработал этот, прежде чем понял, что даже с Regex.escapeпомощью регулярных выражений все равно было бы короче.

->s,c{s.split(?/).zip(c.split ?/).all?{|i,j|i==j||'+#'[j||9]||!j&&c[-1]==?#}}

Попробуйте онлайн!


.*?должен работать вместо [^/]*.
Фонд Моника иск

@NicHartley, который вызовет ложное совпадение критериев a/+/dс темойa/b/c/d
Value Ink

Ах, так и будет. Обертывание в атомарной группе исправляет это, но тогда это на два байта длиннее. Ну что ж.
Фонд Моника иск


1

Python 3 , 72 байта

lambda a,b:bool(re.match(b.translate({43:"[^/]+",35:".+"}),a))
import re

Попробуйте онлайн!

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

РЕДАКТИРОВАТЬ Я придумал 107-байтовое решение, не использующее регулярные выражения. Я не знаю, может ли он стать короче 72 или, может быть, я просто не вижу правильного подхода к этому. Просто структура с разрезом на молнии кажется слишком большой. Попробуйте онлайн!


2
Если последовательность содержит любые другие символы регулярного выражения, это может не сработать. Я бы позаботился об этом, хотя ни один из текущих тестовых примеров не содержит ничего похожего на регулярные выражения.
Value Ink

... как то, f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')что не удается
Джонатан Аллан

Как говорит Value Ink, +/kei$ha/+не совпадает music/kei$ha/latest.
Час Браун

1

Python 2 , 85 84 80 92 89 байт

lambda s,c:all(x in('+','#',y)for x,y in zip(c.split('/')+[0]*-c.find('#'),s.split('/')))

Попробуйте онлайн!

Спасибо Джонатану Аллану и Value Ink за указание на ошибки.


Дает неправильный ответ f('ab', 'abc').
Value Ink

@ Джонатан Аллан: На ​​самом деле, правила говорят: «Количество полей субъекта> = количество полей критериев». Но другие проблемы нуждались в решении ...
Час Браун

О странное правило с учетом проблемы контекста!
Джонатан Аллан

1

Haskell, 76 73 71 67 байт

(a:b)#(c:d)=a=='+'&&b#snd(span(/='/')d)||a=='#'||a==c&&b#d
a#b=a==b

Попробуйте онлайн!

Изменить: -4 байта благодаря @cole.


1
a#b=a==bКажется, работает на несколько байтов меньше, если я что-то упустил
Коул

@cole: да, это работает. Большое спасибо!
Nimi

1

Clojure , 107 91 76 65 102 байт

Анонимная функция возвращает тему как правдивую и nilложную (действует в Clojure).

(defn ?[t c](every? #(#{"#""+"(% 0)}(% 1))(apply #(map vector % %2)(map #(re-seq #"[^/]+" %) [t c]))))

107 102 работает
91 76 65 все побеждены с помощью регулярных символов


... и мой комментарий под вашим вопросом становится уместным
Джонатан Аллан

@JonathanAllan, действительно, кроме + и # не появляются в строках тематических тем :)
Патрик

Я думаю, что это не подходит для предмета music/kei$ha/latestи критериев +/kei$ha/+(который должен соответствовать и является действительным ASCII).
Час Браун

@ChasBrown, правильно, и с ^ вместо $; Спасибо.
Патрик

1
Попробуйте с «\ Q» до и «\ E» после паттерна до замены - источник
Джонатан Аллан


0

Python 3, 99 88 байт

Без использования регулярных выражений. С некоторой помощью Джонатана Аллана и Часа Брауна.

f=lambda s,p:p in(s,'#')or p[:1]in(s[:1],'+')and f(s[1:],p['+'!=p[:1]or(s[:1]in'/')*2:])

f=lambda s,p:s==p or'#'==p[0]or p[0]in(s[0]+'+')and f(s[1:],p['+'!=p[0]or(s[0]=='/')*2:])сохраняет 12. Однако это не обрабатывает некоторые крайние случаи, такие как f('abc/ijk/x', 'abc/+/xyz')или f('abc/ijk/xyz', 'abc/+/x'), которые могут быть исправлены с помощьюf=lambda s,p:s==p or'#'==p[:1]or p[:1]in(s[:1]+'+')and f(s[1:],p['+'!=p[:1]or(s[:1]=='/')*2:])
Джонатан Аллан

Это не для f('abc','ab')и f('abc/de','abc')(оба должны вернуться False, но вместо этого есть IndexError).
Час Браун

...or p[:1]in(s[:1],'+')and...исправляет крайние случаи @ChasBrown, и я указал на стоимость 2 байта.
Джонатан Аллан

Неудачный другой крайний случай завершающего '+' (например f('a/b', 'a/+')), но исправимый в 0 байтах с ...or(s[:1]in'/')*2:]).
Джонатан Аллан

Попробуйте онлайн всегда рекомендуется!
Час Браун

0

Древесный уголь , 36 байт

≔⪪S/θ≔⪪S/ηF∧№η#⊟η≔…θLηθF⌕Aη+§≔θι+⁼θη

Попробуйте онлайн! Ссылка на подробную версию кода. Выходы -(неявный выход Charcoal для true) для совпадения, ничего для совпадения. Объяснение:

≔⪪S/θ

Разделить тему на /с.

≔⪪S/η

Разделить критерии на /с.

F∧№η#⊟η≔…θLηθ

Если критерий содержит (т. Е. Заканчивается), #то удалите его и обрежьте тему до новой длины критерия.

F⌕Aη+§≔θι+

Если критерий содержит, +замените этот элемент в теме с +.

⁼θη

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


0

Сетчатка 0.8.2 , 42 байта

%`$
/
+`^([^/]+/)(.*¶)(\1|\+/)
$2
^¶$|¶#/$

Попробуйте онлайн! Объяснение:

%`$
/

Суффикс /к обеим строкам.

+`^([^/]+/)(.*¶)(\1|\+/)
$2

Повторно удаляйте первый элемент как предмета, так и критерия, пока они равны или элемент критерия является (счастливым) +.

^¶$|¶#/$

Критерии совпадают, если это просто #(с тем, /что было добавлено ранее), в противном случае и тема, и критерии должны быть пустыми к этому моменту.






0

05AB1E , 21 байт

ε'/¡}ζʒ'+å≠}˜'#¡н2ôøË

Ввод в виде списка в порядке [criteria, topic].

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

ε                      # Map both strings in the implicit input-list to:
 '/¡                  '#  Split the string on "/"
                       #   i.e. ["+/+/A/B/#","z/y/A/B/x/w/v/u"]
                       #    → [["+","+","A","B","#"],["z","y","A","B","x","w","v","u"]]
                     # After the map: zip/transpose the two string-lists,
                       # with space as (default) filler
                       #  → [["+","z"],["+","y"],["A","A"],["B","B"],["#","x"],[" ","w"],
                       #     [" ","v"],[" ","u"]]
      ʒ    }           # Filter each pair by:
       '+å≠           '#  Only keep those which do NOT contain a "+"
                       #   → [["A","A"],["B","B"],["#","x"],[" ","w"],[" ","v"],[" ","u"]]
            ˜          # Flatten the filtered list
                       #  → ["A","A","B","B","#","x"," ","w"," ","v"," ","u"]
             '#¡      '# Split the list by "#"
                       #  → [["A","A","B","B"],["x"," ","w"," ","v"," ","u"]]
                н      # Only keep the first part
                       #  → ["A","A","B","B"]
                 2ô    # Split this back into pairs of two
                       #  → [["A","A"],["B","B"]]
                   ø   # Zip/transpose them back
                       #  → [["A","B"],["A","B"]]
                    Ë  # And check if both inner lists are equal
                       #  → 1 (truthy)
                       # (after which the result is output implicitly)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.