Temat pasujący do subskrypcji MQTT

10

tło

MQTT (Message Queuing Telemetry Transport) jest standardowym protokołem przesyłania wiadomości opartym na publikowaniu i subskrypcji ( Wikipedia ).

Każda wiadomość ma temat, na przykład następujące przykłady:

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

Klienci MQTT mogą subskrybować tematy wiadomości za pomocą symboli wieloznacznych:

  • Pojedynczy poziom: +
  • Wszystkie poziomy dalej: #

Na przykład subskrypcja myhome/groundfloor/+/temperatureprzyniosłaby następujące wyniki (niezgodności pogrubione ):

✅ myhome / parter / salon / temperatura
✅ myhome / parter / kuchnia / temperatura
❌ myhome / parter / salon / jasność
❌ myhome / parter / salon / temperatura
garaż / parter / lodówka / temperatura

Natomiast subskrypcja +/groundfloor/#przyniosłaby następujące wyniki:

✅ mójhome / parter / salon / temperatura
✅ mójhome / parter / kuchnia / jasność
✅ garaż / parter / lodówka / temperatura / więcej / konkretne / pola
❌ mójhome / parter / salon / temperatura
❌ mójhome / piwnica / narożnik / temperatura

Więcej informacji tutaj .

Zadanie

Zaimplementuj funkcję / program akceptujący dwa ciągi znaków i zwracający wartość logiczną. Pierwszy ciąg to temat, drugi to temat. W temacie kryteriów używana jest składnia subskrypcji opisana powyżej. Funkcja jest prawdziwa, gdy badany spełnia kryteria.

Zasady tego zadania:

  • Tematy są ASCII
  • Nie ma pól kryteriów poza #symbolem wieloznacznym
  • Symbole wieloznaczne nie pojawiają się w tematach tematycznych
  • Liczba pól tematycznych> = liczba pól kryteriów
  • Nie ma pól 0-znakowych ani przednich lub ukośnych ukośników

Przypadki testowe

kryteria1 = „mójhome / parter / + / temperatura”
kryteria2 = „+ / parter / #”

(„abc”, „ab”) => false
(„abc”, „abc”) => true
(„abc / de”, „abc”) => false
(„mójhome / parter / salon / temperatura”, kryteria1 ) => true
(„mójhome / parter / kuchnia / temperatura”, kryteria 1) => true
(„mójhome / parter / salon / jasność”, kryteria 1) => false
(„mójhome / pierwsze piętro / salon / temperatura”, kryteria1) = > false
(„garaż / parter / lodówka / temperatura”, kryteria 1) => false
(„mójhome / parter / salon / temperatura”, kryteria2) => true
(„mójhome / parter / kuchnia / jasność”, kryteria2) => true
(„garaż / parter / lodówka / temperatura / więcej / specyficzne / pola ”, kryteria2) => prawda
(„ mójhome / pierwsze piętro / salon / temperatura ”, kryteria2) => fałsz
(„mójhome / piwnica / róg / temperatura”, kryteria2) => false
(„muzyka / kei $ ha / najnowsze”, „+ / kei $ ha / +”) => true

Patrick
źródło
@HyperNeutrino, to dobre pytanie. Jestem na płocie. Temat a/b/cnie spełnia kryteriów a/b, więc jestem skłonny powiedzieć Nie .
Patrick
4
Czy gwarantuje się, że /, + i # nigdy nie pojawią się w częściach tematu?
Jonathan Allan
Widzę w blogu podlinkowanym, że „Dodatkowo, sam ukośnik jest prawidłowym tematem”, ale nie ma wzmianki o znakach + i #, więc myślę, że te dwa mogą być.
Jonathan Allan
1
@JathanathanAllan From docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : Znaki wieloznaczne mogą być używane w filtrach tematów, ale NIE MOGĄ być używane w nazwie tematu
Nick Kennedy
2
@NickKennedy - fajne kopanie, ale naprawdę nie powinniśmy.
Jonathan Allan

Odpowiedzi:

3

Galaretka , 20 bajtów

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

Monadyczny link akceptujący listę list znaków [topic, pattern], które zwraca odpowiednio 1lub 0dla dopasowania lub braku dopasowania.

Wypróbuj online! Lub zobacz zestaw testowy .

W jaki sposób?

ṣ€”/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?
Jonathan Allan
źródło
2

Rubinowy , 65 bajtów

Rozwiązanie Regex. Dodałem Regex.escapena wypadek, gdyby nazwa kryterium okazała się być czymś podobnym com.java/string[]/\nlub głupim, który zawierałby wyrażenia regularne.

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

Wypróbuj online!

Rozwiązanie nieregexowe, 77 bajtów

Używa ładnej prostej techniki dzielenia, zamykania i dopasowywania. Opracowałem go najpierw, zanim zdałem sobie sprawę, że nawet przy Regex.escapeużyciu wyrażenia regularnego i tak byłoby ono krótsze.

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

Wypróbuj online!

Wartość tuszu
źródło
.*?powinien działać zamiast [^/]*.
Pozew Fund Moniki w dniu
@NicHartley, który spowoduje fałszywe dopasowanie kryteriów a/+/dz tematema/b/c/d
Value Ink
Ach, tak też będzie. Zawijanie tego w grupę atomową to naprawia, ale potem jest o dwa bajty dłużej. No cóż.
Pozew Fund Moniki w dniu
2

Perl 5 -pl , 50 bajtów

$_="\Q$_";s|\\\+|[^/]+|g;s/\\\#/.*/;$_=<>=~m|^$_$|

Wypróbuj online!

Xcali
źródło
mała poprawka, <>=~/^$_$/na koniec
Nahuel Fouilleul
1

Python 3 , 72 bajty

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

Wypróbuj online!

Ten problem można w prosty sposób uprościć do dopasowania wyrażenia regularnego, chociaż inna bardziej interesująca metoda może dać lepsze wyniki.

EDYCJA Wymyśliłem 107-bajtowe rozwiązanie bez użycia wyrażenia regularnego. Nie wiem, czy może być krótszy niż 72, a może po prostu nie widzę poprawnego podejścia do tego. Jednak sama struktura podzielonego zamka wydaje się zbyt duża. Wypróbuj online!

HyperNeutrino
źródło
2
Jeśli sekwencja zawiera inne znaki regularne, może się to nie powieść. Uważam na to, mimo że żaden z obecnych przypadków testowych nie zawiera niczego zdalnie przypominającego wyrażenie regularne.
Wartość tuszu
... jak f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')co się nie udaje
Jonathan Allan
Jak mówi Value Ink, +/kei$ha/+nie pasuje music/kei$ha/latest.
Chas Brown
1

Python 2 , 85 84 80 92 89 bajtów

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

Wypróbuj online!

Podziękowania dla Jonathana Allana i Value Ink za wskazanie błędów.

Chas Brown
źródło
Podaje złą odpowiedź f('ab', 'abc').
Wartość tuszu
@Jonathan Allan: W rzeczywistości zasady mówią „Liczba pól tematów> = liczba pól kryteriów”. Ale inne problemy wymagały naprawy ...
Chas Brown,
Och, dziwna zasada, biorąc pod uwagę kontekst problemu!
Jonathan Allan
1

Haskell, 76 73 71 67 bajtów

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

Wypróbuj online!

Edycja: -4 bajty dzięki @cole.

nimi
źródło
1
a#b=a==bwydaje się działać o kilka bajtów mniej, chyba że czegoś mi brakuje
cole
@cole: tak, to działa. Wielkie dzięki!
nimi
1

Clojure , 107 91 76 65 102 bajtów

Anonimowa funkcja zwraca temat jako prawdomówny i nilfalsey (obowiązuje w Clojure).

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

107 102 pracuje
91 76 65 wszystkich pokonanych z znakami regularnymi

Patrick
źródło
... i mój komentarz pod twoim pytaniem staje się trafny
Jonathan Allan
@JonathanAllan, rzeczywiście, z wyjątkiem + i # nie pojawiają się w ciągach tematów :)
Patrick
Myślę, że to nie pasuje do tematu music/kei$ha/latesti kryteriów +/kei$ha/+(które powinny pasować i są zgodne z ASCII).
Chas Brown
@ChasBrown, popraw, z ^ zamiast $; dzięki.
Patrick
1
Spróbuj użyć „\ Q” przed i „\ E” po wzorcu przed zastąpieniem - źródło
Jonathan Allan
0

Kotlin , 106 bajtów

fun f(s:List<String>)=s[1].split("/").filterIndexed{i,v->v!="+"&&v!="#"&&v!=s[0].split("/")[i]}.count()==0

Wypróbuj online!

Quinn
źródło
0

Python 3, 99 88 bajtów

Bez użycia wyrażenia regularnego. Z pomocą Jonathana Allana i Chasa Browna.

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:])
RootTwo
źródło
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:])oszczędza 12. Jednak to nie przetwarza niektórych przypadków krawędzi, takich jak f('abc/ijk/x', 'abc/+/xyz')lub f('abc/ijk/xyz', 'abc/+/x'), które można naprawić za pomocą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:])
Jonathan Allan
To się nie udaje f('abc','ab')i f('abc/de','abc')(oba powinny wrócić False, ale zamiast tego jest IndexError).
Chas Brown
...or p[:1]in(s[:1],'+')and...naprawia przypadki krawędzi @ChasBrown i wskazałem na koszt 2 bajtów.
Jonathan Allan
Nie spełnia innego przypadku końcowego „+” (np. f('a/b', 'a/+')), Ale można go naprawić za pomocą 0 bajtów ...or(s[:1]in'/')*2:]).
Jonathan Allan
Wypróbuj online jest zawsze zalecane!
Chas Brown,
0

Węgiel drzewny , 36 bajtów

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

Wypróbuj online! Link jest do pełnej wersji kodu. Wyjścia -(wynik domyślny dla Węgla true) dla dopasowania, nic dla braku dopasowania. Wyjaśnienie:

≔⪪S/θ

Podziel temat na /s.

≔⪪S/η

Podziel kryteria na /s.

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

Jeśli kryteria zawierają (tzn. Kończą się na) #a, usuń je i przytnij obiekt do nowej długości kryteriów.

F⌕Aη+§≔θι+

Jeżeli kryteria zawierają, +zamień ten element w temacie na +.

⁼θη

Porównaj temat z kryteriami i pośrednio wydrukuj wynik.

Neil
źródło
0

Retina 0.8.2 , 42 bajty

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

Wypróbuj online! Wyjaśnienie:

%`$
/

Przyrostek a /do obu linii.

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

Wielokrotnie usuwaj pierwszy element zarówno podmiotu, jak i kryterium, gdy są one równe lub element kryteriów jest (szczęśliwy) +.

^¶$|¶#/$

Kryteria są zgodne, jeśli jest to tylko #(z /dodanym wcześniej), w przeciwnym razie zarówno temat, jak i kryteria powinny być puste do tego momentu.

Neil
źródło
0

Galaretka , 22 19 bajtów

ḟ”+ṣ”/)ZẠƇṖœi”#$¿ZE

Wypróbuj online!

Łącze monadyczne, które przyjmuje jako argument [topic], [criterion]i zwraca 1dopasowanie i 0brak dopasowania.

Nick Kennedy
źródło
0

JavaScript, 69 66 bajtów

t=>s=>new RegExp(s.split`+`.join`[^/]+`.split`#`.join`.+`).test(t)

Wypróbuj online!

darrylyeo
źródło
Nie odnosi się to do tematu music/kei$ha/latesti kryteriów +/kei$ha/+(które powinny być zgodne i są zgodne z ASCII).
Chas Brown
0

Python 3 , 149 148 bajtów

def f(t,c):t,c=t.split('/'),c.split('/');return all([c[i]=='+'or c[i]==t[i]or c[i]=='#'for i in range(len(c))])and not(len(c)!=len(t)and c[-1]!='#')

Wypróbuj online!

Dat
źródło
0

05AB1E , 21 bajtów

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

Wprowadź jako listę w kolejności [criteria, topic].

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

ε                      # 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)
Kevin Cruijssen
źródło