Corrispondenza argomento abbonamento MQTT


10

sfondo

MQTT (trasporto di telemetria di accodamento messaggi) è un protocollo di messaggistica basato su pubblicazione e sottoscrizione ( Wikipedia ) standard ISO .

Ogni messaggio ha un argomento, ad esempio i seguenti esempi:

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

I client MQTT possono iscriversi agli argomenti dei messaggi utilizzando i caratteri jolly:

  • Livello singolo: +
  • Tutti i livelli in poi: #

Ad esempio, l'abbonamento myhome/groundfloor/+/temperatureprodurrebbe questi risultati (non conformità in grassetto ):

✅ myhome / piano terra / soggiorno / temperatura
✅ myhome / piano terra / cucina / temperatura
❌ myhome / piano terra / soggiorno / luminosità
myhome / primo piano / soggiorno / temperatura
garage / piano terra / frigorifero / temperatura

Considerando che l'abbonamento +/groundfloor/#produrrebbe questi risultati:

✅ myhome / piano terra / soggiorno / temperatura
✅ myhome / piano terra / cucina / luminosità
✅ garage / piano terra / frigorifero / temperatura / altro / specifico / campi
myhome / firstfloor / soggiorno / temperatura
casa / seminterrato / angolo / temperatura

Maggiori informazioni qui .

L'obiettivo

Implementare una funzione / programma che accetta due stringhe e restituisce un valore booleano. La prima stringa è l'argomento soggetto, la seconda è l'argomento criteri. L'argomento dei criteri utilizza la sintassi dell'abbonamento descritta sopra. La funzione è vera quando il soggetto soddisfa i criteri.

Regole per questa attività:

  • Gli argomenti sono ASCII
  • Non ci sono campi criteri oltre il #carattere jolly
  • I caratteri jolly non vengono visualizzati negli argomenti
  • Numero di campi tematici> = numero di campi criteri
  • Non ci sono campi a 0 caratteri né barre in avanti o in coda

Casi test

criteri1 = "myhome / groundfloor / + / temperature"
criterio2 = "+ / groundfloor / #"

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("myhome / groundfloor / livingroom / temperature", criterio1 ) => true
("myhome / groundfloor / kitchen / temperature", criterio1) => true
("myhome / groundfloor / livingroom / luminosità", criterio1) => false
("myhome / firstfloor / livingroom / temperature", criterio1) = > false
("garage / piano terra / frigorifero / temperatura", criteri1) => false
("casa / piano terra / soggiorno / temperatura", criteri2) => vero
("casa / piano terra / cucina / luminosità", criteri2) => vero
("garage / piano terra / frigorifero / temperatura / altro / specifici / campi ", criterio2) => vero
(" casa / primo piano / soggiorno / temperatura ", criterio2) => falso
("myhome / seminterrato / angolo / temperatura", criterio2) => false
("music / kei $ ha / latest", "+ / kei $ ha / +") => true


@HyperNeutrino, questa è una buona domanda. Sono sul recinto. Il soggetto a/b/cnon corrisponderebbe ai criteri a/b, quindi sono propenso a dire di no .
Patrick,

4
/, + E # sono garantiti non compariranno mai nelle parti dell'argomento?
Jonathan Allan,

Vedo nel blog collegato che "Inoltre, solo la barra in avanti è un argomento valido", ma nessuna menzione di + e #, quindi immagino che questi due possano esserlo.
Jonathan Allan,

1
@JonathanAllan Da docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : i caratteri jolly possono essere utilizzati nei filtri degli argomenti, ma NON DEVONO essere utilizzati all'interno di un nome argomento
Nick Kennedy,

2
@NickKennedy - bello scavare, ma non dovremmo davvero aver bisogno.
Jonathan Allan,

Risposte:


3

Gelatina , 20 byte

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

Un collegamento monadico che accetta un elenco di elenchi di caratteri [topic, pattern], che restituisce 1o rispettivamente 0per corrispondenza o nessuna corrispondenza.

Provalo online! O vedi una suite di test .

Come?

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

Rubino , 65 byte

Soluzione Regex. Ho aggiunto Regex.escapenel caso in cui un nome di criterio fosse così com.java/string[]/\no qualcosa di stupido che avrebbe pezzi regex.

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

Provalo online!

Soluzione non regex, 77 byte

Utilizza una bella tecnica semplice di divisione, zip e abbinamento. Ho sviluppato questo prima di rendermi conto che anche con Regex.escapela soluzione regex sarebbe stato comunque più breve.

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

Provalo online!


.*?dovrebbe funzionare al posto di [^/]*.
Finanzia la causa di Monica il

@NicHartley che attiverà una falsa corrispondenza per i criteri a/+/dcon argomentoa/b/c/d
Value Ink

Ah, così sarà. L'avvolgimento in un gruppo atomico lo risolve, ma poi è più lungo di due byte. Oh bene.
Finanzia la causa di Monica il


1

Python 3 , 72 byte

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

Provalo online!

Questo problema può essere banalmente semplificato in una corrispondenza regex, sebbene un altro metodo più interessante possa produrre risultati migliori.

EDIT Ho trovato una soluzione a 107 byte che non utilizza regex. Non so se può essere inferiore a 72 o forse non vedo solo come correggere questo approccio. Tuttavia, solo la struttura con zip divisa sembra essere troppo grande. Provalo online!


2
Se la sequenza contiene altri caratteri regex, ciò potrebbe non riuscire. Lo farei notare anche se nessuno degli attuali casi di test contiene qualcosa di simile a regex da remoto.
Value Ink

... come quello f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')che fallisce
Jonathan Allan il

Come dice Value Ink, +/kei$ha/+non corrisponde music/kei$ha/latest.
Chas Brown,

1

Python 2 , 85 84 80 92 89 byte

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

Provalo online!

Grazie a Jonathan Allan e Value Ink per aver segnalato i bug.


Fornisce la risposta sbagliata f('ab', 'abc').
Value Ink,

@Jonathan Allan: In realtà, le regole dicono 'Numero di campi tematici> = numero di campi criteri'. Ma altri problemi dovevano essere risolti ...
Chas Brown,

Oh strana regola dato il contesto del problema!
Jonathan Allan,

1

Haskell, 76 73 71 67 byte

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

Provalo online!

Modifica: -4 byte grazie a @cole.


1
a#b=a==bsembra funzionare per pochi byte in meno, a meno che non mi manchi qualcosa
Cole

@cole: sì, funziona. Molte grazie!
nimi,

1

Clojure , 107 91 76 65 102 byte

Una funzione anonima, restituisce argomento come verità e nilfalsità (valido in Clojure).

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

107 102 funzionante
91 76 65 tutti sconfitti con caratteri regex


... e il mio commento sotto la tua domanda diventa pertinente
Jonathan Allan,

@JonathanAllan, infatti, tranne + e # non compaiono nelle stringhe di argomenti in oggetto :)
Patrick,

Penso che questo fallisca per soggetto music/kei$ha/lateste criteri +/kei$ha/+(che dovrebbe corrispondere ed è valido ASCII).
Chas Brown,

@ChasBrown, corretto, e con ^ invece di $; Grazie.
Patrick,

1
Prova con '\ Q' prima e '\ E' dopo lo schema prima della sostituzione - fonte
Jonathan Allan,


0

Python 3, 99 88 byte

Senza usare una regex. Con l'aiuto di Jonathan Allan e 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:])

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:])salva 12. Tuttavia, questo non riesce a elaborare alcuni casi limite come f('abc/ijk/x', 'abc/+/xyz')o f('abc/ijk/xyz', 'abc/+/x'), che possono essere risolti conf=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,

Questo fallisce per f('abc','ab')e f('abc/de','abc')(entrambi dovrebbero tornare False, ma invece c'è un IndexError).
Chas Brown,

...or p[:1]in(s[:1],'+')and...risolve i casi limite @ChasBrown e ho sottolineato per un costo di 2 byte.
Jonathan Allan,

Non riesce un altro caso limite di un '+' finale (ad es. f('a/b', 'a/+')) Ma risolvibile in 0 byte con ...or(s[:1]in'/')*2:]).
Jonathan Allan,

Provalo online è sempre consigliato!
Chas Brown,

0

Carbone , 36 byte

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

Provalo online! Il collegamento è alla versione dettagliata del codice. Output -(output implicito del carbone per true) per una corrispondenza, niente per nessuna corrispondenza. Spiegazione:

≔⪪S/θ

Dividi il soggetto su /s.

≔⪪S/η

Dividi i criteri su /s.

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

Se il criterio contiene (cioè termina con) a, #rimuoverlo e tagliare il soggetto alla nuova lunghezza dei criteri.

F⌕Aη+§≔θι+

Dove i criteri contengono +quindi sostituire quell'elemento nell'argomento con +.

⁼θη

Confronta il soggetto con i criteri e stampa implicitamente il risultato.


0

Retina 0.8.2 , 42 byte

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

Provalo online! Spiegazione:

%`$
/

Basta aggiungere a /ad entrambe le righe.

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

Rimuovi ripetutamente il primo elemento sia del soggetto che dei criteri mentre sono uguali o l'elemento criterio è un (felice) +.

^¶$|¶#/$

I criteri corrispondono se è solo un #(con quello /che è stato aggiunto in precedenza), altrimenti sia il soggetto che i criteri dovrebbero essere vuoti a questo punto.



0

Gelatina , 22 19 byte

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

Provalo online!

Un collegamento monadico che prende come argomento [topic], [criterion]e ritorna 1per una corrispondenza e 0per nessuna corrispondenza.


0

JavaScript, 69 66 byte

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

Provalo online!


Ciò non riesce per soggetto music/kei$ha/lateste criteri +/kei$ha/+(che devono corrispondere ed è valido ASCII).
Chas Brown,

0

Python 3 , 149 148 byte

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

Provalo online!


0

05AB1E , 21 byte

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

Immettere come elenco nell'ordine [criteria, topic] .

Provalo online o verifica tutti i casi di test .

Spiegazione:

ε                      # 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.