MQTT abonelik konusu eşleşmesi


10

Arka fon

MQTT (Message Queuing Telemetri Taşımacılığı), ISO standart yayımlama-abone olma tabanlı ileti protokolüdür ( Wikipedia ).

Her iletinin aşağıdaki örnekler gibi bir konusu vardır:

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

MQTT istemcileri joker karakterler kullanarak ileti konularına abone olabilir:

  • Tek seviye: +
  • Tüm seviyeler: #

Örneğin, abonelik myhome/groundfloor/+/temperatureşu sonuçları üretir (uyumsuzluklar kalın harflerle gösterilir ):

✅ myhome / groundfloor / oturma odası / sıcaklık
✅ myhome / groundfloor / mutfak / sıcaklık
❌ myhome / groundfloor / salon / parlaklık
❌ myhome / firstfloor / salon / sıcaklık
garaj / groundfloor / buzdolabı / sıcaklık

Abonelik +/groundfloor/#şu sonuçları verirken :

✅ myhome / groundfloor / livingroom / temperature
✅ myhome / groundfloor / kitchen / brightness
✅ garaj / groundfloor / buzdolabı / sıcaklık / daha fazla / spesifik / alanlar
❌ myhome / firstfloor / livingroom / temperature
❌ myhome / bodrum / köşe / sıcaklık

Daha fazla bilgi burada .

Görev

İki dizeyi kabul eden ve bir boole döndüren bir işlev / program uygulayın. İlk dize konu başlığı, ikincisi ölçüt konusudur. Ölçüt konusu, yukarıda ayrıntıları verilen abonelik sözdizimini kullanır. Konu ölçütlerle eşleştiğinde işlev doğrudur.

Bu görevin kuralları:

  • Konular ASCII
  • #Joker karakterin ötesinde herhangi bir ölçüt alanı yok
  • Joker karakterler konu başlıklarında görünmüyor
  • Konu alanı sayısı> = ölçüt alanı sayısı
  • 0 karakterli alan yok veya öne eğik çizgi yok

Test senaryoları

ölçüt1 = "evim / zemin kat / + / sıcaklık"
ölçüt2 = "+ / zemin kat / #"

("abc", "ab") => yanlış
("abc", "abc") => true
("abc / de", "abc") => yanlış
("myhome / groundfloor / livingroom / temperature", ölçüt1 ) => true
("myhome / groundfloor / kitchen / temperature", ölçüt1
) => true
("myhome / groundfloor / livingroom / brightness", ölçüt1 ) => false ("myhome / firstfloor / livingroom / temperature", ölçüt1) = > false
("garaj / zemin katı / buzdolabı / sıcaklık", ölçüt1) => false
("myhome / groundfloor / livingroom / temperature", ölçüt2) => true
("myhome / groundfloor / kitchen / brightness", ölçüt2) => true
("garaj / zemin / buzdolabı / sıcaklık / daha fazla / spesifik / alanlar ",
ölçüt2 ) => true (" myhome / firstfloor / livingroom / temperature ", ölçüt2) => yanlış
("myhome / bodrum / köşe / sıcaklık", ölçüt2) => yanlış
("müzik / kei $ ha / son", "+ / kei $ ha / +") => doğru


@HyperNeutrino, bu iyi bir soru. Ben çitin üzerindeyim. Konu a/b/cölçütlerle eşleşmiyor a/b, bu yüzden Hayır demeye meyilliyim .
Patrick

4
/, + Ve # öğelerinin konu bölümlerinde asla görünmeyeceği garanti ediliyor mu?
Jonathan Allan

Blogda "Ek olarak, sadece eğik çizgi geçerli bir konudur" ama + ve # bahsetmiyorum bağlantılı olduğunu görüyorum, bu yüzden bu ikisi olabilir sanırım.
Jonathan Allan

1
Gönderen @JonathanAllan docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/... : Joker karakterleri Konu Filtreler kullanılabilir, ancak bir konu Adı içinde kullanılmış olmamalıdır
Nick Kennedy

2
@NickKennedy - güzel kazma, ama gerçekten ihtiyacımız yok.
Jonathan Allan

Yanıtlar:


3

Jöle , 20 bayt

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

Karakter listelerin bir listesini kabul Bir monadic Link [topic, pattern], hangi döner 1veya 0maç veya sırasıyla no-maç için.

Çevrimiçi deneyin! Veya bir test takımına bakın .

Nasıl?

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

Regex çözeltisi. Regex.escapeBir ölçüt adının com.java/string[]/\n, normal ifadeler içeren aptalca veya aptalca bir şey olması durumunda ekledim .

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

Çevrimiçi deneyin!

Normal olmayan çözüm, 77 bayt

Güzel, basit bir bölme, zip ve eşleme tekniği kullanır. Regex.escapeRegex çözümü ile bile yine de daha kısa olacağını fark etmeden önce bunu geliştirdim .

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

Çevrimiçi deneyin!


.*?yerine çalışması gerekir [^/]*.
Monica'nın Davası

@NicHartley, a/+/dkonu ile ilgili ölçütler için yanlış bir eşleşme tetikleyeceka/b/c/d
Value Ink

Ah, öyle olacak. Bunu bir atom grubunda sarmak bunu düzeltir, ama sonra iki bayt daha uzundur. Oh iyi.
Monica'nın Davası


1

Python 3 , 72 bayt

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

Çevrimiçi deneyin!

Daha ilginç bir yöntem daha iyi sonuçlar üretse de, bu sorun normal bir regex eşleşmesine basitçe basitleştirilebilir.

EDIT Regex kullanmayan 107 baytlık bir çözüm buldum. 72'den daha kısa olabilir mi bilmiyorum ya da belki de doğru yaklaşımı görmüyorum. Ancak bölünmüş fermuar yapısı çok büyük görünüyor. Çevrimiçi Deneyin!


2
Dizi başka regex karakterleri içeriyorsa, bu başarısız olabilir. Mevcut test senaryolarının hiçbirinde uzaktan normal ifade benzeri bir şey bulunmasa da bununla ilgilenirim.
Değer Mürekkebi

... f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')başarısız olan gibi
Jonathan Allan

Value Ink'in dediği +/kei$ha/+gibi eşleşmiyor music/kei$ha/latest.
Chas Brown

1

Python 2 , 85 84 80 92 89 bayt

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

Çevrimiçi deneyin!

Böcekleri işaret ettiği için Jonathan Allan ve Value Ink'e teşekkürler .


Yanlış cevap veriyor f('ab', 'abc').
Değer Mürekkebi

@Jonathan Allan: Aslında kurallar 'Konu alanı sayısı> = ölçüt alanı sayısı' diyor. Ama diğer sorunların düzeltilmesi gerekiyor ...
Chas Brown

Ah garip kural sorun bağlamında verilen!
Jonathan Allan

1

Haskell, 76 73 71 67 bayt

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

Çevrimiçi deneyin!

Düzenleme: @cole sayesinde -4 bayt.


1
a#b=a==bBir şey eksik olmadıkça birkaç bayt daha az çalışıyor gibi görünüyor
cole

@cole: evet, işe yarıyor. Çok teşekkürler!
nimi

1

Clojure , 107 91 76 65 102 bayt

Anonim bir işlev, konu başlığını doğruluk ve falsey olarak döndürür nil( Clojure'da geçerlidir).

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

107 102 çalışma
91 76 65 hepsi normal ifade karakterleriyle mağlup edildi


... ve sorunuzun altında benim yorum ilgili olur
Jonathan Allan

@JonathanAllan, gerçekten, + ve # hariç konu başlık dizelerinde görünmüyor :)
Patrick

Bunun konu music/kei$ha/latestve kriterler için başarısız olduğunu düşünüyorum +/kei$ha/+(bu eşleşmeli ve geçerli ASCII)
Chas Brown

@ChasBrown, düzeltmek ve $ yerine ^; Teşekkürler.
Patrick

1
Değiştirmeden önce desenden önce '\ Q' ve '\ E' ile deneyin - kaynak
Jonathan Allan


0

Python 3, 99 88 bayt

Normal ifade kullanmadan. Jonathan Allan ve Chas Brown'ın yardımıyla.

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:])Ancak , f('abc/ijk/x', 'abc/+/xyz')veya f('abc/ijk/xyz', 'abc/+/x')ile düzeltilebilen bazı uç durumları işleyemezf=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

Bu başarısız olur f('abc','ab')ve f('abc/de','abc')(her ikisi de dönmelidir False, ancak bunun yerine bir vardır IndexError).
Chas Brown

...or p[:1]in(s[:1],'+')and...@ChasBrown kenar kasalarını düzeltir ve 2 baytlık bir maliyete dikkat çektim.
Jonathan Allan

Sondaki '+' (örn. f('a/b', 'a/+')) Başka bir kenar durumunda başarısız olur ancak 0 bayt ile sabitlenebilir ...or(s[:1]in'/')*2:]).
Jonathan Allan

Her zaman çevrimiçi deneyin tavsiye edilir!
Chas Brown

0

Kömür , 36 bayt

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

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı versiyonudur. Bir maç -için Çıktılar (Kömürün örtük çıktısı true), maç için hiçbir şey yok. Açıklama:

≔⪪S/θ

Konuyu /s üzerine bölün .

≔⪪S/η

Ölçütleri /s.

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

Ölçütler a içeriyorsa (yani bitiyorsa) #a'yı kaldırın ve özneyi ölçütlerin yeni uzunluğuna getirin.

F⌕Aη+§≔θι+

Ölçütlerin +yer aldığı durumlarda konudaki öğeyi değiştirin +.

⁼θη

Konuyu ölçütlerle karşılaştırın ve sonucu dolaylı olarak yazdırın.


0

Retina 0.8.2 , 42 bayt

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

Çevrimiçi deneyin! Açıklama:

%`$
/

/Her iki satıra da sonek .

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

Hem öznenin hem de ölçütün ilk öğesini eşitken veya ölçüt öğesi bir (mutlu) olduğunda tekrar tekrar kaldırın +.

^¶$|¶#/$

Ölçütler yalnızca #( /daha önce eklenmiş olanlarla) eşleşirse, aksi takdirde hem konu hem de ölçütler bu noktaya kadar boş olmalıdır.



0

Jöle , 22 19 bayt

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

Çevrimiçi deneyin!

Onun argüman olarak alan bir monadic bağlantı [topic], [criterion]ve döndüren 1bir maç için ve 0hiçbir maç için.


0

JavaScript, 69 66 bayt

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

Çevrimiçi deneyin!


Bu konu music/kei$ha/latestve kriterler için başarısız olur +/kei$ha/+(eşleşmelidir ve geçerli ASCII'dir).
Chas Brown

0

Piton 3 , 149 148 bayt

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

Çevrimiçi deneyin!


0

05AB1E , 21 bayt

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

Sırayla liste olarak girin [criteria, topic].

Çevrimiçi deneyin veya tüm test senaryolarını doğrulayın .

Açıklama:

ε                      # 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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.