Übereinstimmung des MQTT-Abonnementthemas

10

Hintergrund

MQTT (Message Queuing Telemetry Transport) ist ein ISO-Standard-Messaging-Protokoll auf Publish-Subscribe-Basis ( Wikipedia ).

Jede Nachricht hat ein Thema, z. B. die folgenden Beispiele:

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

MQTT-Clients können Nachrichtenthemen mithilfe von Platzhaltern abonnieren:

  • Einstufig: +
  • Alle Ebenen ab: #

Das Abonnement myhome/groundfloor/+/temperaturewürde beispielsweise folgende Ergebnisse liefern (Abweichungen in Fettdruck ):

✅ myhome / Erdgeschoss / Wohnzimmer / Temperatur
✅ myhome / Erdgeschoss / Küche / Temperatur
❌ myhome / Erdgeschoss / Wohnzimmer / Helligkeit
❌ myhome / erstes Stockwerk / Wohnzimmer / Temperatur
Garage / Erdgeschoss / Kühlschrank / Temperatur

Während das Abonnement +/groundfloor/#diese Ergebnisse hervorbringen würde:

✅ myhome / Erdgeschoss / Wohnzimmer / Temperatur
✅ myhome / Erdgeschoss / Küche / Helligkeit
✅ Garage / Erdgeschoss / Kühlschrank / Temperatur / mehr / spezifische / Felder
❌ myhome / Firstfloor / Wohnzimmer / Temperatur
❌ myhome / Keller / Ecke / Temperatur

Mehr Infos hier .

Die Aufgabe

Implementieren Sie eine Funktion / ein Programm, die / das zwei Zeichenfolgen akzeptiert und einen Booleschen Wert zurückgibt. Die erste Zeichenfolge ist das Thema, die zweite das Kriterienthema. Das Kriterienthema verwendet die oben beschriebene Abonnementsyntax. Die Funktion ist wahr, wenn das Thema den Kriterien entspricht.

Regeln für diese Aufgabe:

  • Themen sind ASCII
  • Es gibt keine Kriterienfelder außerhalb des #Platzhalters
  • Platzhalter werden in Themenbereichen nicht angezeigt
  • Anzahl der Themenfelder> = Anzahl der Kriterienfelder
  • Es gibt keine Felder mit 0 Zeichen und keine Schrägstriche

Testfälle

Kriterien1 = "myhome / Erdgeschoss / + / Temperatur"
Kriterien2 = "+ / Erdgeschoss / #"

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("myhome / Erdgeschoss / Wohnzimmer / Temperatur", Kriterien1 ) => wahr
("myhome / erdgeschoss / küche / temperatur", kriterien1) => wahr
("myhome / erdgeschoss / wohnzimmer / helligkeit", kriterien1) => falsch
("myhome / erster Stock / wohnzimmer / temperatur", kriterien1) = > false
("Garage / Erdgeschoss / Kühlschrank / Temperatur", Kriterien1) => false
("myhome / Erdgeschoss / Wohnzimmer / Temperatur", Kriterien2) => true
("myhome / Erdgeschoss / Küche / Helligkeit", Kriterien2) => true
("Garage / Erdgeschoss / Kühlschrank / Temperatur / mehr / spezifisch / Felder ", Kriterien2) => wahr
(" myhome / erster Stock / Wohnzimmer / Temperatur ", Kriterien2) => falsch
("myhome / Keller / Ecke / Temperatur", Kriterien2) => false
("Musik / Kei $ ha / Neueste", "+ / Kei $ ha / +") => true

Patrick
quelle
@ HyperNeutrino, das ist eine gute Frage. Ich bin am Zaun. Das Thema a/b/cwürde nicht den Kriterien entsprechen a/b, daher neige ich dazu, Nein zu sagen .
Patrick
4
Werden /, + und # garantiert nie in Themenbereichen angezeigt?
Jonathan Allan
Ich sehe im Blog verlinkt, dass "Zusätzlich ist der Schrägstrich allein ein gültiges Thema", aber keine Erwähnung von + und #, also denke ich, dass diese beiden sein können.
Jonathan Allan
1
@JonathanAllan Von docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : Die Platzhalterzeichen können in Themenfiltern verwendet werden, dürfen aber NICHT innerhalb eines Themennamens verwendet werden
Nick Kennedy
2
@ NickKennedy - schönes Graben, aber wir sollten es wirklich nicht brauchen.
Jonathan Allan

Antworten:

3

Gelee , 20 Bytes

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

Ein monadischer Link, der eine Liste von Zeichenlisten akzeptiert [topic, pattern], die zurückgegeben werden 1oder 0für Übereinstimmung bzw. Nichtübereinstimmung.

Probieren Sie es online aus! Oder sehen Sie sich eine Testsuite an .

Wie?

ṣ€”/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
quelle
2

Ruby , 65 Bytes

Regex-Lösung. Ich fügte hinzu, Regex.escapefalls ein Kriterienname zufällig so etwas wie com.java/string[]/\noder etwas Dummes ist, das Regex-Stücke haben würde.

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

Probieren Sie es online aus!

Nicht-Regex-Lösung, 77 Bytes

Verwendet eine schöne einfache Split-, Zip- und Match-Technik. Ich habe diese zuerst entwickelt, bevor mir klar wurde, dass selbst mit Regex.escapeder Regex-Lösung sowieso kürzer gewesen wäre.

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

Probieren Sie es online aus!

Wert Tinte
quelle
.*?sollte anstelle von arbeiten [^/]*.
Fund Monica Klage
@NicHartley, die eine falsche Übereinstimmung für Kriterien a/+/dmit Thema auslösen wirda/b/c/d
Wert Tinte
Ah, so wird es. Wenn Sie das in eine Atomgruppe einwickeln, wird das behoben, aber dann sind es zwei Bytes länger. Naja.
Fund Monica Klage
1

Python 3 , 72 Bytes

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

Probieren Sie es online aus!

Dieses Problem kann trivial zu einer Regex-Übereinstimmung vereinfacht werden, obwohl eine andere interessantere Methode möglicherweise bessere Ergebnisse liefert.

BEARBEITEN Ich habe eine 107-Byte-Lösung ohne Regex entwickelt. Ich weiß nicht, ob es kürzer als 72 werden kann, oder vielleicht sehe ich einfach nicht, wie ich das richtig korrigieren soll. Nur die Split-Zip-Struktur scheint jedoch zu groß zu sein. Probieren Sie es online aus!

HyperNeutrino
quelle
2
Wenn die Sequenz andere Regex-Zeichen enthält, schlägt dies möglicherweise fehl. Ich würde darauf achten, obwohl keiner der aktuellen Testfälle irgendetwas entfernt Regex-ähnliches enthält.
Wert Tinte
... wie f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')das scheitert
Jonathan Allan
Wie Value Ink sagt, +/kei$ha/+stimmt nicht überein music/kei$ha/latest.
Chas Brown
1

Python 2 , 85 84 80 92 89 Bytes

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

Probieren Sie es online aus!

Vielen Dank an Jonathan Allan und Value Ink für den Hinweis auf Fehler.

Chas Brown
quelle
Gibt die falsche Antwort auf f('ab', 'abc').
Wert Tinte
@ Jonathan Allan: Tatsächlich sagen die Regeln "Anzahl der Betrefffelder> = Anzahl der Kriterienfelder". Aber andere Probleme mussten behoben werden ...
Chas Brown
Oh seltsame Regel angesichts des Problemkontexts!
Jonathan Allan
1

Haskell, 76 73 71 67 Bytes

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

Probieren Sie es online aus!

Bearbeiten: -4 Bytes dank @cole.

Nimi
quelle
1
a#b=a==bscheint für ein paar Bytes weniger zu funktionieren, es sei denn, ich vermisse etwas
Cole
@ Cole: Ja, das funktioniert. Vielen Dank!
Nimi
1

Clojure , 107 91 76 65 102 Bytes

Eine anonyme Funktion gibt das Thema als wahr und nilals falsch zurück (gültig in Clojure).

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

107 102 arbeiten
91 76 65 alle mit Regex-Zeichen besiegt

Patrick
quelle
... und mein Kommentar unter Ihrer Frage wird relevant
Jonathan Allan
@ JonathanAllan, in der Tat, außer + und # erscheinen nicht in Themenstrings :)
Patrick
Ich denke, dies schlägt für Thema music/kei$ha/latestund Kriterien fehl +/kei$ha/+(die übereinstimmen sollten und ASCII gültig sind).
Chas Brown
@ChasBrown, korrekt und mit ^ anstelle von $; Vielen Dank.
Patrick
1
Versuchen Sie es mit '\ Q' vor und '\ E' nach dem Muster vor dem Ersetzen - Quelle
Jonathan Allan
0

Kotlin , 106 Bytes

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

Probieren Sie es online aus!

Quinn
quelle
0

Python 3, 99 88 Bytes

Ohne Verwendung eines regulären Ausdrucks. Mit etwas Hilfe von Jonathan Allan und Chas Brown.

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
quelle
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:])spart 12. Dies kann jedoch einige Randfälle wie f('abc/ijk/x', 'abc/+/xyz')oder nicht verarbeiten f('abc/ijk/xyz', 'abc/+/x'), die mitf=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
Dies schlägt für f('abc','ab')und fehl f('abc/de','abc')(beide sollten zurückkehren False, aber stattdessen gibt es eine IndexError).
Chas Brown
...or p[:1]in(s[:1],'+')and...behebt die Randfälle @ChasBrown und ich wies auf Kosten von 2 Bytes hin.
Jonathan Allan
Fehlschlägt einen anderen Randfall eines nachgestellten '+' (z. B. f('a/b', 'a/+')), kann jedoch in 0 Bytes mit behoben werden ...or(s[:1]in'/')*2:]).
Jonathan Allan
Probieren Sie es online wird immer empfohlen!
Chas Brown
0

Holzkohle , 36 Bytes

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

Probieren Sie es online aus! Der Link führt zur ausführlichen Version des Codes. Ausgaben -(die implizite Ausgabe von Charcoal für true) für eine Übereinstimmung, nichts für keine Übereinstimmung. Erläuterung:

≔⪪S/θ

Teilen Sie das Thema auf /s.

≔⪪S/η

Teilen Sie die Kriterien auf /s.

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

Wenn das Kriterium a enthält (dh mit a endet), #entfernen Sie es und schneiden Sie das Motiv auf die neue Länge des Kriteriums.

F⌕Aη+§≔θι+

Wenn das Kriterium enthält, +ersetzen Sie dieses Element im Betreff durch +.

⁼θη

Vergleichen Sie das Thema mit den Kriterien und drucken Sie das Ergebnis implizit aus.

Neil
quelle
0

Retina 0,8,2 , 42 Bytes

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

Probieren Sie es online aus! Erläuterung:

%`$
/

Suffix a /in beide Zeilen.

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

Entfernen Sie wiederholt das erste Element sowohl des Betreffs als auch der Kriterien, während sie gleich sind oder das Kriterienelement a (glücklich) ist +.

^¶$|¶#/$

Die Kriterien stimmen überein, wenn es sich nur um ein #(mit dem /zuvor hinzugefügten) handelt, andernfalls sollten sowohl das Thema als auch die Kriterien zu diesem Zeitpunkt leer sein.

Neil
quelle
0

Gelee , 22 19 Bytes

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

Probieren Sie es online aus!

Ein monadischer Link, der als Argument dient [topic], [criterion]und 1für eine Übereinstimmung und 0für keine Übereinstimmung zurückkehrt.

Nick Kennedy
quelle
0

JavaScript, 69 66 Bytes

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

Probieren Sie es online aus!

darrylyeo
quelle
Dies schlägt für Betreff music/kei$ha/latestund Kriterien fehl +/kei$ha/+(die mit ASCII übereinstimmen sollten und gültig sind).
Chas Brown
0

Python 3 , 149 148 Bytes

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]!='#')

Probieren Sie es online aus!

Dat
quelle
0

05AB1E , 21 Bytes

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

Eingabe als Liste in der Reihenfolge [criteria, topic].

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung:

ε                      # 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
quelle