Kecocokan topik berlangganan MQTT

10

Latar Belakang

MQTT (pesan antrian Telemetry Transportasi) adalah standar ISO mempublikasikan-berlangganan berbasis protokol pesan ( Wikipedia ).

Setiap pesan memiliki topik, seperti contoh berikut:

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

Klien MQTT dapat berlangganan topik pesan menggunakan wildcard:

  • Tingkat tunggal: +
  • Semua tingkat ke depan: #

Misalnya, langganan myhome/groundfloor/+/temperatureakan menghasilkan hasil ini (ketidaksesuaian dalam huruf tebal ):

✅ myhome / groundfloor / ruang tamu / suhu
✅ myhome / groundfloor / dapur / suhu
❌ myhome / groundfloor / ruang tamu / kecerahan
❌ myhome / firstfloor / ruang tamu / suhu
garasi / groundfloor / kulkas / suhu

Sedangkan langganan +/groundfloor/#akan menghasilkan hasil ini:

✅ myhome / groundfloor / ruang tamu / suhu
✅ myhome / groundfloor / dapur / kecerahan
✅ garasi / groundfloor / kulkas / suhu / lebih / spesifik / bidang
❌ myhome / firstfloor / ruang tamu / suhu
❌ myhome / basement / sudut / suhu

Info lebih lanjut di sini .

Tugas

Menerapkan fungsi / program menerima dua string dan mengembalikan boolean. String pertama adalah topik pembicaraan, yang kedua adalah topik kriteria. Topik kriteria menggunakan sintaks berlangganan yang dijelaskan di atas. Fungsi ini benar ketika subjek cocok dengan kriteria.

Aturan untuk tugas ini:

  • Topiknya adalah ASCII
  • Tidak ada bidang kriteria di luar #wildcard
  • Wildcard tidak muncul dalam topik subjek
  • Jumlah bidang subjek> = jumlah bidang kriteria
  • Tidak ada bidang 0 karakter atau garis miring depan atau belakang

Uji kasus

criteria1 = "myhome / groundfloor / + / temperature"
criteria2 = "+ / groundfloor / #"

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("myhome / groundfloor / livingroom / temperature", criteria1 ) => true
("myhome / groundfloor / kitchen / temperature", criteria1) => true
("myhome / groundfloor / livingroom / brightness", criteria1) => false
("myhome / firstfloor / livingroom / temperature", criteria1) = > false
("garasi / groundfloor / lemari es / suhu", criteria1) => false
("myhome / groundfloor / livingroom / temperature", criteria2) => true
("myhome / groundfloor / kitchen / brightness", criteria2) => true
("garasi / groundfloor / lemari es / suhu / lebih / spesifik / bidang ", criteria2) => true
(" myhome / firstfloor / livingroom / temperature ", criteria2) => false
("myhome / basement / sudut / suhu", criteria2) => false
("musik / kei $ ha / terbaru", "+ / kei $ ha / +") => true

Patrick
sumber
@HyperNeutrino, itu pertanyaan yang bagus. Saya di pagar. Subjek a/b/ctidak akan cocok dengan kriteria a/b, jadi saya cenderung mengatakan Tidak .
Patrick
4
Apakah /, + dan # dijamin tidak akan pernah muncul di bagian topik?
Jonathan Allan
Saya melihat di blog yang terhubung bahwa "Selain itu, garis miring saja adalah topik yang valid" tetapi tidak menyebutkan + dan #, jadi saya kira keduanya bisa.
Jonathan Allan
1
@JonathanAllan Dari docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : Karakter wildcard dapat digunakan dalam Filter Topik, tetapi TIDAK HARUS digunakan dalam Nama Topik
Nick Kennedy
2
@NickKennedy - penggalian yang bagus, tetapi kita seharusnya tidak perlu melakukannya.
Jonathan Allan

Jawaban:

3

Jelly , 20 byte

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

Tautan monadik yang menerima daftar daftar karakter [topic, pattern], yang masing-masing mengembalikan 1atau 0untuk pertandingan atau yang tidak cocok.

Cobalah online! Atau lihat test-suite .

Bagaimana?

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

Ruby , 65 byte

Solusi Regex. Saya menambahkan Regex.escapekalau-kalau nama kriteria kebetulan sesuatu seperti com.java/string[]/\natau sesuatu yang konyol yang akan memiliki potongan regex.

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

Cobalah online!

Solusi non-regex, 77 byte

Menggunakan teknik split, zip, dan match sederhana yang bagus. Saya mengembangkan ini terlebih dahulu sebelum menyadarinyaRegex.escape solusi regex akan lebih pendek.

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

Cobalah online!

Nilai Tinta
sumber
.*?harus bekerja di tempat [^/]*.
Dana Gugatan Monica
@NicHartley yang akan memicu kecocokan palsu untuk kriteria a/+/ddengan topika/b/c/d
Nilai Tinta
Ah, jadi itu akan terjadi. Membungkus itu dalam sebuah kelompok atom memperbaikinya, tetapi kemudian itu dua byte lebih lama. Baiklah.
Dana Gugatan Monica
2

Perl 5 -pl , 50 byte

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

Cobalah online!

Xcali
sumber
perbaikan kecil, <>=~/^$_$/pada akhirnya
Nahuel Fouilleul
1

Python 3 , 72 byte

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

Cobalah online!

Masalah ini dapat disederhanakan sepele menjadi pertandingan regex, meskipun metode lain yang lebih menarik dapat menghasilkan hasil yang lebih baik.

EDIT Saya datang dengan solusi 107-byte tidak menggunakan regex. Saya tidak tahu apakah bisa lebih pendek dari 72 atau mungkin saya hanya tidak melihat untuk memperbaiki pendekatan ini. Hanya struktur split-zip tampaknya terlalu besar. Cobalah secara Online!

HyperNeutrino
sumber
2
Jika urutan berisi karakter regex lain, ini mungkin gagal. Saya akan mewaspadai itu meskipun tidak ada kasus uji saat ini yang mengandung sesuatu yang mirip regex.
Nilai Tinta
... seperti f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')yang gagal
Jonathan Allan
Seperti yang dikatakan Value Ink, +/kei$ha/+tidak cocok 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('/')))

Cobalah online!

Terima kasih kepada Jonathan Allan dan Value Ink untuk menunjukkan bug.

Chas Brown
sumber
Memberi jawaban yang salah f('ab', 'abc').
Nilai Tinta
@ Jonathan Allan: Sebenarnya, aturan mengatakan 'Jumlah bidang subjek> = jumlah bidang kriteria'. Tapi masalah lain perlu diperbaiki ...
Chas Brown
Oh aturan aneh mengingat konteks masalahnya!
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

Cobalah online!

Edit: -4 bytes berkat @cole.

nimi
sumber
1
a#b=a==btampaknya bekerja untuk beberapa byte lebih sedikit, kecuali saya kehilangan sesuatu
cole
@cole: ya, itu berhasil. Terima kasih banyak!
nimi
1

Clojure , 107 91 76 65 102 byte

Fungsi anonim, mengembalikan topik topik sebagai kebenaran dan nilsebagai kesalahan (berlaku di Clojure).

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

107 102 bekerja
91 76 65 semuanya dikalahkan dengan regex chars

Patrick
sumber
... dan komentar saya di bawah pertanyaan Anda menjadi relevan
Jonathan Allan
@ Jonathan Allan, memang, kecuali + dan # tidak muncul dalam topik topik :)
Patrick
Saya pikir ini gagal untuk subjek music/kei$ha/latestdan kriteria +/kei$ha/+(yang harus cocok dan valid ASCII).
Chas Brown
@ ChasBrown, benar, dan dengan ^ bukannya $; Terima kasih.
Patrick
1
Coba dengan '\ Q' sebelum dan '\ E' setelah pola sebelum sumber
Jonathan Allan
0

Kotlin , 106 byte

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

Cobalah online!

Quinn
sumber
0

Python 3, 99 88 byte

Tanpa menggunakan regex. Dengan bantuan dari Jonathan Allan dan 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
sumber
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:])menghemat 12. Namun ini gagal untuk memproses beberapa kasus tepi seperti f('abc/ijk/x', 'abc/+/xyz')atau f('abc/ijk/xyz', 'abc/+/x'), yang dapat diperbaiki denganf=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
Ini gagal untuk f('abc','ab')dan f('abc/de','abc')(keduanya harus kembali False, tetapi sebaliknya ada IndexError).
Chas Brown
...or p[:1]in(s[:1],'+')and...memperbaiki kasus tepi @ChasBrown dan saya tunjukkan untuk biaya 2 byte.
Jonathan Allan
Gagal kasus tepi lain dari trailing '+' (misalnya f('a/b', 'a/+')) tetapi dapat diperbaiki dalam 0 byte dengan ...or(s[:1]in'/')*2:]).
Jonathan Allan
Cobalah secara online selalu disarankan!
Chas Brown
0

Arang , 36 byte

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

Cobalah online! Tautan adalah untuk mengucapkan versi kode. Output -(output implisit Charcoal untuk true) untuk pertandingan, tidak ada yang cocok. Penjelasan:

≔⪪S/θ

Bagi subjek menjadi /s.

≔⪪S/η

Bagi kriteria pada /s.

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

Jika kriteria berisi (yaitu diakhiri dengan), #maka lepaskan dan potong subjek sesuai dengan panjang kriteria yang baru.

F⌕Aη+§≔θι+

Di mana kriteria berisi +kemudian ganti elemen itu dalam subjek dengan +.

⁼θη

Bandingkan subjek dengan kriteria dan cetak hasilnya secara implisit.

Neil
sumber
0

Retina 0.8.2 , 42 byte

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

Cobalah online! Penjelasan:

%`$
/

Akhiran a /untuk kedua baris.

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

Secara berulang-ulang hapus elemen pertama dari subjek dan kriteria sementara mereka sama atau elemen kriteria adalah (bahagia) +.

^¶$|¶#/$

Kriteria cocok jika hanya a #(dengan /yang ditambahkan sebelumnya) jika tidak, subjek dan kriteria harus kosong pada titik ini.

Neil
sumber
0

Jelly , 22 19 byte

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

Cobalah online!

Tautan monadik yang mengambil sebagai argumennya [topic], [criterion]dan kembali 1untuk pertandingan dan 0tanpa pertandingan.

Nick Kennedy
sumber
0

JavaScript, 69 66 byte

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

Cobalah online!

Darrylyeo
sumber
Ini gagal untuk subjek music/kei$ha/latestdan kriteria +/kei$ha/+(yang harus cocok dan valid 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]!='#')

Cobalah online!

Dat
sumber
0

05AB1E , 21 byte

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

Masukkan sebagai daftar dalam urutan [criteria, topic].

Cobalah secara online atau verifikasi semua kasus uji .

Penjelasan:

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