Збіг тем підписки на MQTT


10

Фон

MQTT (Телевізійний транспорт у черзі повідомлень) - стандарт ISO-протоколу обміну повідомленнями на основі публікації та підписки ( Вікіпедія ).

Кожне повідомлення має тему, наприклад такі приклади:

  • 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призведе до цих результатів (невідповідності жирним шрифтом ):

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

Тоді як підписка +/groundfloor/#призведе до таких результатів:

✅ MyHome / цокольний / вітальня / температура
✅ MyHome / цокольний / кухня / яскравість
✅ гараж / цокольний / холодильник / температури / більш / конкретних / полів
❌ MyHome / firstfloor / вітальня / температура
❌ MyHome / підвал / кут / температура

Більше інформації тут .

Завдання

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

Правила цього завдання:

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

Тестові справи

Критерії1 = "мій будинок / перший поверх / + / температура"
критерії2 = "+ / перший поверх / #"

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("мій будинок / перший поверх / вітальня / температура", критерії1 ) => true
("мій будинок / перший поверх / кухня / температура", критерії1) => true
("мій будинок / перший поверх / вітальня / яскравість", критерії1) => false
("мій будинок / перший поверх / вітальня / температура", критерії1) = > false
("гараж /
цокольний поверх / холодильник / температура", критерії1) => false ("мій будинок / цокольний поверх / вітальня / температура", критерії2) => вірно
("мій будинок / цокольний поверх / кухня / яскравість", критерії2) => вірно
("гараж / перший поверх / холодильник / температура / більше / конкретний / поля ", критерії2) => вірно
(" мій будинок / перший поверх / вітальня / температура ", критерії2) => помилково
("мій будинок / підвал / кут / температура", критерії2) => false
("музика / kei $ ha / остання", "+ / kei $ ha / +") => вірно


@HyperNeutrino, це хороше питання. Я на паркані. Тема a/b/cне відповідає критеріям a/b, тому я схильний сказати « Ні» .
Патрік

4
Чи /, + та # гарантовано ніколи не з’являються у розділах теми?
Джонатан Аллан

Я бачу в блозі, пов’язаному з тим, що "Додатково, лише поперечна коса риса є вагомою темою", але жодних згадок про + та #, тому я думаю, що це може бути.
Джонатан Аллан

1
@JonathanAllan From 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

Спробуйте в Інтернеті!

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

EDIT Я придумав 107-байтове рішення, не використовуючи регулярного вираження. Я не знаю, чи може це зробити коротше 72 або, можливо, я просто не бачу правильного підходу до цього. Просто здається, що структура розділеного zip занадто велика. Спробуйте в Інтернеті!


2
Якщо послідовність містить будь-які інші символи регулярного вираження, це може бути невдалим. Я б з цим звернув увагу, хоча жоден з нинішніх тестових випадків не містить нічого, схожого на віддалений вираз.
Значення чорнила

... як, 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').
Значення чорнила

@Jonathan Allan: Насправді правила говорять "Кількість предметних полів> = кількість полів критеріїв". Але інші проблеми потребували виправлення ...
Chas Brown

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

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

@cole: так, це працює. Дуже дякую!
Nimi

1

Clojure , 107 91 76 65 102 байт

Анонімна функція повертає тему теми як truthy та 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η+§≔θι+⁼θη

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

≔⪪S/θ

Розділити тему на /s.

≔⪪S/η

Розбийте критерії на /s.

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

Якщо критерій містить (тобто закінчується), а #потім видаліть його та обріжте тему до нової довжини критеріїв.

F⌕Aη+§≔θι+

Якщо критерії містять, +замініть цей елемент на предмет +.

⁼θη

Порівняйте тему з критеріями та неявно друкуйте результат.


0

Сітківка 0,8,2 , 42 байти

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

Спробуйте в Інтернеті! Пояснення:

%`$
/

Суфікс a /до обох рядків.

+`^([^/]+/)(.*¶)(\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.