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


@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?

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!


.*?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


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!


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.


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.


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


... 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

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:])

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.


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.



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.


0

JavaScript, 69 66 byte

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

Cobalah online!


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!


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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.