จับคู่หัวข้อการสมัคร MQTT


10

พื้นหลัง

MQTT (Message Queuing Telemetry Transport) เป็นโปรโตคอลการรับส่งข้อความแบบบอกรับสมาชิกที่ใช้มาตรฐาน ISO ( Wikipedia )

แต่ละข้อความมีหัวข้อเช่นตัวอย่างต่อไปนี้:

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

ลูกค้า MQTT อาจสมัครสมาชิกหัวข้อข้อความโดยใช้สัญลักษณ์แทน:

  • ระดับเดียว: +
  • ทุกระดับเป็นต้นไป: #

ตัวอย่างเช่นการสมัครสมาชิกmyhome/groundfloor/+/temperatureจะสร้างผลลัพธ์เหล่านี้ (ไม่สอดคล้องตามตัวหนา ):

✅ myhome / ชั้นล่าง / ห้องรับแขก / อุณหภูมิ
✅ myhome / ชั้นล่าง / ห้องครัว / อุณหภูมิ
❌ myhome / ชั้นล่าง / ห้องรับแขก / ความสว่าง
❌ myhome / ชั้นแรก / ห้องรับแขก / อุณหภูมิ
โรงรถ / พื้น / ตู้เย็น / อุณหภูมิ

ในขณะที่การสมัครสมาชิก+/groundfloor/#จะให้ผลลัพธ์เหล่านี้:

✅ myhome / ชั้นล่าง / ห้องรับแขก / อุณหภูมิ
✅ myhome / groundfloor / ครัว / ความสว่าง
✅โรงรถ / พื้น / ตู้เย็น / อุณหภูมิ / เพิ่มเติม / เฉพาะ / สาขา
❌ myhome / firstfloor / ห้องรับแขก / อุณหภูมิ
❌ myhome / ชั้นใต้ดิน / มุม / อุณหภูมิ

ข้อมูลเพิ่มเติมที่นี่

งาน

ใช้ฟังก์ชั่น / โปรแกรมที่ยอมรับสองสตริงและส่งคืนบูลีน สตริงแรกคือหัวข้อเรื่องที่สองคือหัวข้อเกณฑ์ หัวข้อเกณฑ์ใช้ไวยากรณ์การสมัครสมาชิกซึ่งมีรายละเอียดด้านบน ฟังก์ชั่นนี้เป็นจริงเมื่อวัตถุนั้นตรงกับเกณฑ์

กฎสำหรับงานนี้:

  • หัวข้อคือ ASCII
  • ไม่มีฟิลด์เงื่อนไขนอกเหนือจาก#สัญลักษณ์ตัวแทน
  • สัญลักษณ์แทนไม่ปรากฏในหัวข้อเรื่อง
  • จำนวนฟิลด์หัวเรื่อง> = จำนวนฟิลด์เกณฑ์
  • ไม่มีฟิลด์ 0 อักขระหรือสแลชนำหน้าหรือต่อท้าย

กรณีทดสอบ

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

("abc", "ab") => false
("abc", "abc") => true
("abc / de", "abc") => false
("myhome / groundfloor / ห้องรับแขก / อุณหภูมิ", criteria1 ) => จริง
("myhome / groundfloor / ครัว / อุณหภูมิ", criteria1) => จริง
("myhome / groundfloor / ห้องรับแขก / ความสว่าง", criteria1) => false
("myhome / firstfloor / ห้องรับแขก / อุณหภูมิ", criteria1) = > false
("โรงรถ / พื้น / ตู้เย็น / อุณหภูมิ", criteria1) => false
("myhome / groundfloor / ห้องรับแขก / อุณหภูมิ", criteria2) => จริง
("myhome / groundfloor / ครัว / ความสว่าง", criteria2) => true
("โรงรถ / ชั้นล่าง / ตู้เย็น / อุณหภูมิ / เพิ่มเติม / เฉพาะ / ฟิลด์ ", criteria2) => จริง
(" myhome / firstfloor / ห้องรับแขก / อุณหภูมิ ", criteria2) => false
("myhome / basement / corner / อุณหภูมิ", criteria2) => false
("music / kei $ ha / ล่าสุด", "+ / kei $ ha / +") => true


@HyperNeutrino นั่นเป็นคำถามที่ดี ฉันอยู่บนรั้ว เรื่องa/b/cจะไม่ตรงกับเกณฑ์a/bดังนั้นฉันมีความโน้มเอียงที่จะบอกว่าไม่มี
Patrick

4
/, + และ # รับประกันว่าจะไม่ปรากฏในส่วนหัวข้อหรือไม่
Jonathan Allan

ฉันเห็นในบล็อกที่ลิงก์ว่า "นอกจากนี้เครื่องหมายสแลชเพียงอย่างเดียวเป็นหัวข้อที่ถูกต้อง" แต่ไม่มีการกล่าวถึง + และ # ดังนั้นฉันจึงเดาว่าทั้งสองนี้อาจเป็นได้
Jonathan Allan

1
@JonathanAllanจากdocs.oasis-open.org/mqtt/mqtt/v3.1.1/os/ … : สามารถใช้อักขระตัวแทนในตัวกรองหัวข้อ แต่ไม่ควรใช้ภายในชื่อหัวข้อ
Nick Kennedy

2
@NickKennedy - ขุดได้ดี แต่เราไม่จำเป็นต้องทำ
Jonathan Allan

คำตอบ:


3

เยลลี่ 20 ไบต์

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

ลิงค์แบบ monadic ยอมรับรายการของตัวละคร[topic, pattern]ซึ่งจะส่งกลับ1หรือ0จับคู่หรือไม่จับคู่ตามลำดับ

ลองออนไลน์! หรือดูการทดสอบในตัว

อย่างไร?

ṣ€”/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 ไบต์

โซลูชัน Regex ฉันเพิ่มRegex.escapeในกรณีที่ชื่อเกณฑ์เพียงเพื่อให้เป็นสิ่งที่ชอบcom.java/string[]/\nหรือสิ่งที่โง่ที่จะมีชิ้นส่วน regex

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

ลองออนไลน์!

โซลูชันที่ไม่ใช่ regex 77 ไบต์

ใช้เทคนิคการแบ่งซิปและการจับคู่ที่ดี ฉันพัฒนาอันนี้ก่อนที่จะตระหนักว่าแม้จะมีRegex.escapeวิธีการ regex จะสั้นลงอย่างไรก็ตาม

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

ลองออนไลน์!


.*?[^/]*ควรจะทำงานในสถานที่ของ
คดีของกองทุนโมนิกา

@NicHartley ที่จะเรียกการจับคู่ที่ผิดพลาดสำหรับเกณฑ์ที่a/+/dมีหัวข้อa/b/c/d
หมึกมูลค่า

อามันจะ การห่อสิ่งนั้นในกลุ่มอะตอมแก้ไขได้ แต่จากนั้นจะมีความยาวสองไบต์ โอ้ดี
คดีฟ้องร้องกองทุนโมนิก้า


1

Python 3 , 72 ไบต์

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

ลองออนไลน์!

ปัญหานี้สามารถทำให้การจับคู่ regex ง่ายขึ้นเล็กน้อย แต่วิธีการที่น่าสนใจอีกวิธีหนึ่งอาจให้ผลลัพธ์ที่ดีกว่า

แก้ไขฉันมากับวิธีแก้ปัญหา 107- ไบต์ไม่ใช้ regex ฉันไม่รู้ว่ามันจะสั้นกว่า 72 หรือบางทีฉันแค่ไม่เห็นวิธีการแก้ไขที่ถูกต้อง โครงสร้างการแบ่งซิปดูเหมือนจะใหญ่เกินไป ลองออนไลน์!


2
หากลำดับมีอักขระ regex อื่น ๆ สิ่งนี้อาจล้มเหลว ฉันจะระวังสิ่งนั้นแม้ว่าจะไม่มีกรณีทดสอบใด ๆ ในปัจจุบันที่บรรจุสิ่งที่คล้าย regex จากระยะไกล
Value Ink

... f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')สิ่งที่ล้มเหลว
Jonathan Allan

เป็นค่าหมึกกล่าวว่าไม่ตรงกับ+/kei$ha/+ music/kei$ha/latest
Chas Brown

1

Python 2 , 85 84 80 92 89 ไบต์

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

ลองออนไลน์!

ขอบคุณJonathan AllanและValue Inkสำหรับการชี้จุดบกพร่อง


ให้คำตอบที่ผิดf('ab', 'abc')ไป
Value Ink

@Janathan Allan: อันที่จริงแล้วกฎพูดว่า 'จำนวนฟิลด์เรื่อง> = จำนวนฟิลด์เกณฑ์' แต่ปัญหาอื่น ๆ ก็จำเป็นต้องได้รับการแก้ไข ...
Chas Brown

โอ้กฎแปลก ๆ ให้บริบทของปัญหา!
Jonathan Allan

1

Haskell, 76 73 71 67 ไบต์

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

ลองออนไลน์!

แก้ไข: -4 ไบต์ขอบคุณ @cole


1
a#b=a==bดูเหมือนว่าจะทำงานน้อยลงสักสองสามไบต์เว้นแต่ฉันจะพลาดบางสิ่งบางอย่าง
โคล

@ คูล: ใช่มันใช้งานได้ ขอบคุณมาก!
nimi

1

Clojure , 107 91 76 65 102 ไบต์

ฟังก์ชั่นที่ไม่ระบุชื่อส่งกลับหัวข้อเรื่องเป็นความจริงและnilเป็นเท็จ (ใช้ได้ใน Clojure)

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

107 102ทำงาน
91 76 65ทุกคนพ่ายแพ้กับตัวอักษร regex


... และความคิดเห็นของฉันภายใต้คำถามของคุณจะกลายเป็นประเด็น
Jonathan Allan

@JonathanAllan แน่นอนยกเว้น + และ # จะไม่ปรากฏในสตริงหัวข้อเรื่อง :)
แพทริค

ฉันคิดว่าสิ่งนี้ล้มเหลวสำหรับหัวเรื่องmusic/kei$ha/latestและเกณฑ์+/kei$ha/+(ซึ่งควรตรงกันและเป็น ASCII ที่ถูกต้อง)
Chas Brown

@ChasBrown ถูกต้องและมี ^ แทน $; ขอบคุณ
แพทริค

1
ลองด้วย '\ Q' ก่อนและ '\ E' ตามรูปแบบก่อนที่จะเปลี่ยน - แหล่งที่มา
Jonathan Allan


0

Python 3, 99 88 ไบต์

โดยไม่ต้องใช้ regex ด้วยความช่วยเหลือจาก Jonathan Allan และ 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:])ประหยัด 12 อย่างไรก็ตามสิ่งนี้ล้มเหลวในการประมวลผลกรณีขอบบางอย่างเช่นf('abc/ijk/x', 'abc/+/xyz')หรือf('abc/ijk/xyz', 'abc/+/x')ซึ่งสามารถแก้ไขได้f=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

สิ่งนี้ล้มเหลวf('abc','ab')และf('abc/de','abc')(ทั้งคู่ควรกลับมาFalseแต่มีข้อผิดพลาดIndexError)
Chas Brown

...or p[:1]in(s[:1],'+')and...แก้ไขกรณีขอบ @ChasBrown และฉันชี้ให้เห็นค่าใช้จ่าย 2 ไบต์
โจนาธานอัลลัน

ล้มเหลวในกรณีอื่นขอบของท้าย '+' (เช่นf('a/b', 'a/+')) แต่แน่นอนใน 0 ...or(s[:1]in'/')*2:])ไบต์ด้วย
Jonathan Allan

ลองออนไลน์แนะนำเสมอ!
Chas Brown

0

ถ่าน , 36 ไบต์

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

ลองออนไลน์! การเชื่อมโยงคือการใช้รหัสเวอร์ชันอย่างละเอียด เอา-ท์พุท (เอาท์พุทโดยนัยของ Charcoal true) สำหรับการแข่งขันไม่มีอะไรที่จะไม่ตรงกัน คำอธิบาย:

≔⪪S/θ

แยกเรื่องใน/s

≔⪪S/η

แยกเกณฑ์ใน/s

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

หากเกณฑ์มี (เช่นลงท้ายด้วย) a ให้#ลบออกและตัดแต่งหัวเรื่องตามความยาวใหม่ของเกณฑ์

F⌕Aη+§≔θι+

ที่ไหนมีเกณฑ์ที่แล้วแทนที่องค์ประกอบว่าในเรื่องที่มี++

⁼θη

เปรียบเทียบหัวเรื่องกับเกณฑ์และพิมพ์ผลลัพธ์โดยปริยาย


0

เรติน่า 0.8.2 , 42 ไบต์

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

ลองออนไลน์! คำอธิบาย:

%`$
/

เติม a /ไปทั้งสองบรรทัด

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

ซ้ำแล้วซ้ำอีกเอาองค์ประกอบแรกของทั้งสองเรื่องและเกณฑ์ในขณะที่พวกเขาเท่ากับหรือองค์ประกอบเกณฑ์คือ +(ความสุข)

^¶$|¶#/$

เกณฑ์ตรงกับหากเป็นเพียงแค่#(ที่มีการ/เพิ่มก่อนหน้านี้) มิฉะนั้นทั้งหัวเรื่องและเกณฑ์ควรว่างเปล่าในจุดนี้




0

JavaScript, 69 66 ไบต์

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

ลองออนไลน์!


สิ่งนี้ล้มเหลวสำหรับหัวเรื่องmusic/kei$ha/latestและเกณฑ์+/kei$ha/+(ซึ่งควรตรงกันและเป็น ASCII ที่ถูกต้อง)
Chas Brown


0

05AB1E , 21 ไบต์

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

[criteria, topic]ป้อนข้อมูลรายชื่อในการสั่งซื้อ

ลองมันออนไลน์หรือตรวจสอบกรณีทดสอบทั้งหมด

คำอธิบาย:

ε                      # 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.