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 / groundfloor / 거실 / 온도
✅ myhome / groundfloor / 주방 / 온도
❌ myhome / groundfloor / 거실 / 명도
❌ myhome / firstfloor / 거실 / 온도
차고 / groundfloor / 냉장고 / 온도

구독 +/groundfloor/#은 다음과 같은 결과를 생성합니다.

✅ 인 MyHome / groundfloor에 / 거실 / 온도
✅ 인 MyHome / groundfloor에 / 부엌 / 밝기
✅ 주차장 / groundfloor에 / 냉장고 / 온도 / 이상 / 별 / 필드
❌ 인 MyHome / firstfloor / 거실 / 온도
❌ 인 MyHome / 지하 / 코너 / 온도

자세한 내용은 여기를 참조하십시오 .

작업

두 개의 문자열을 수락하고 부울을 리턴하는 함수 / 프로그램을 구현하십시오. 첫 번째 문자열은 주제 주제이고 두 번째 문자열은 기준 주제입니다. 기준 주제는 위에서 자세히 설명한 구독 구문을 사용합니다. 주제가 기준과 일치 할 때 기능은 진실합니다.

이 작업에 대한 규칙 :

  • 주제는 ASCII입니다
  • #와일드 카드 이외의 기준 필드가 없습니다
  • 와일드 카드는 주제 주제에 나타나지 않습니다
  • 주제 필드 수> = 기준 필드 수
  • 0 자 필드 나 선행 또는 후행 슬래시가 없습니다.

테스트 사례

기준 1 = "myhome / groundfloor / + / 온도"
기준 2 = "+ / groundfloor / #"

( "abc", "ab") => false
( "abc", "abc") => true
( "abc / de", "abc") => false
( "myhome / groundfloor / livingroom / temperature", 기준 1 ) => true
( "myhome / groundfloor / 부엌 / 온도", 기준 1) => true
( "myhome / groundfloor / 거실 / 밝기", 기준 1) => false
( "myhome / firstfloor / 거실 / 온도", 기준 1) = > false
( "차고 / 지상층 / 냉장고 / 온도", 기준 1) => false
( "myhome / 지상층 / 거실 / 온도", 기준 2) => true
( "myhome / 지상층 / 주방 / 밝기", 기준 2) => true
( "차고 / 지상층 / 냉장고 / 온도 / 기타 / 특정 / 필드 ", 기준 2) => true
("myhome / 1 층 / 거실 / 온도 ", 기준 2) => 거짓
( "myhome / 지하실 / 코너 / 온도", 기준 2) => false
( "music / kei $ ha / latest", "+ / kei $ ha / +") => true


@HyperNeutrino, 좋은 질문입니다. 나는 울타리에있다. 피험자 a/b/c는 기준 a/b에 맞지 않기 때문에 아니오 라고 말하는 경향이 있습니다.
Patrick

4
주제 부분에 /, + 및 #이 절대로 나타나지 않습니까?
Jonathan Allan

블로그에서 "추가로 슬래시만으로는 유효한 주제입니다."라는 링크가 있지만 +와 #에 대해서는 언급 할 수 없습니다.
Jonathan Allan

1
@JonathanAllan from docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/… : 와일드 카드 문자는 토픽 필터에 사용할 수 있지만 토픽 이름 내에 사용해서는 안됩니다.
Nick Kennedy

2
@NickKennedy-멋진 파기, 그러나 우리는 정말로 필요하지 않습니다.
Jonathan Allan

답변:


3

젤리 , 20 바이트

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

문자리스트의 목록을 받아들이는 모나드 링크, [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

루비 , 65 바이트

정규식 솔루션. 나는 Regex.escape기준 이름이 그렇게 com.java/string[]/\n정규식 조각을 가질 만한 것과 같 거나 어리석은 경우가 있다고 덧붙였다 .

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

온라인으로 사용해보십시오!

비정규 솔루션, 77 바이트

멋진 간단한 분할, 우편 및 일치 기술을 사용합니다. Regex.escape정규식 솔루션 을 사용하더라도 어쨌든 짧을 것이라는 것을 깨닫기 전에이 것을 먼저 개발했습니다 .

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

온라인으로 사용해보십시오!


.*?대신에 작동해야합니다 [^/]*.
기금 모니카의 소송

@NicHartley a/+/d주제와의 기준에 맞지 않는 일치를 유발합니다a/b/c/d
Value Ink

아, 그래. 원자 그룹에서 랩핑하면 수정되지만 2 바이트가 더 깁니다. 오 잘
Fund Monica의 소송


1

파이썬 3 , 72 바이트

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

온라인으로 사용해보십시오!

이 문제는 정규식 일치로 간단하게 단순화 할 수 있지만 더 흥미로운 다른 방법으로 더 나은 결과를 얻을 수 있습니다.

편집 정규식을 사용하지 않는 107 바이트 솔루션을 생각해 냈습니다. 그것이 72보다 짧아 질 수 있는지 또는 아마도 이것에 대한 올바른 접근법을 보지 못할 수도 있습니다. 분할 지퍼 구조 만 너무 큰 것 같습니다. 온라인으로 사용해보십시오!


2
시퀀스에 다른 정규식 문자가 포함되어 있으면 실패 할 수 있습니다. 현재 테스트 사례 중 어느 것도 원격으로 정규식과 같은 것을 포함하지는 않지만 그 사실을 알아 냈습니다.
가치 잉크

... f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')실패한 것처럼
Jonathan Allan

Value Ink에 따르면 +/kei$ha/+일치하지 않습니다 music/kei$ha/latest.
Chas Brown

1

파이썬 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 AllanValue Ink 에게 감사합니다 .


에 잘못된 답변을 제공합니다 f('ab', 'abc').
밸류 잉크

@Jonathan Allan : 실제로 규칙에는 '제목 필드 수> = 기준 필드 수'가 있습니다. 그러나 다른 문제는 수정이 필요했습니다 ...
Chas Brown

문제의 상황이 주어진 이상한 규칙!
Jonathan Allan

1

하스켈, 76 73 71 67 바이트

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

온라인으로 사용해보십시오!

편집 : @cole 덕분에 -4 바이트.


1
a#b=a==b내가 빠진 것이 아니라면 몇 바이트 더 적게 작동하는 것 같습니다
cole

@ Cole : 예, 잘 작동합니다. 고마워요!
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)는 모든 문자 정규식 격파


... 그리고 질문에서 내 댓글이 해당된다
조나단 앨런

@JonathanAllan, 실제로 +와 #을 제외하고는 주제 주제 문자열에 나타나지 않습니다 :)
Patrick

주제 music/kei$ha/latest와 기준 +/kei$ha/+(이와 일치해야하며 유효한 ASCII)에 대해서는 이것이 실패한다고 생각합니다 .
Chas Brown

@ChasBrown은 정확하고 $ 대신 ^를 사용합니다. 감사.
Patrick

1
바꾸기 전 패턴 뒤에 '\ Q'와 '\ E'를 시도해보십시오. – 소스
Jonathan Allan


0

파이썬 3, 99 88 바이트

정규식을 사용하지 않고. 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:])
조나단 앨런

이것은에 실패 f('abc','ab')하고 f('abc/de','abc')(둘 다 반환해야 False하지만 대신가 있습니다 IndexError).
Chas Brown

...or p[:1]in(s[:1],'+')and...가장자리 케이스 @ChasBrown을 수정하고 2 바이트의 비용을 지적했습니다.
Jonathan Allan

후행 '+'(예 :)의 다른 엣지 케이스에 실패 f('a/b', 'a/+')하지만로 0 바이트로 수정할 수 ...or(s[:1]in'/')*2:])있습니다.
Jonathan Allan


0

, 36 바이트

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

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 출력 -(숯의 암시 출력 true일치하는 경우), 아니 일치 아무것도. 설명:

≔⪪S/θ

/s로 피사체를 분할하십시오 .

≔⪪S/η

의 기준을 /s로 나눕니다.

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

기준이 포함 된 경우 (즉, 끝으로) a #를 제거하고 기준의 새 길이로 주제를 다듬습니다.

F⌕Aη+§≔θι+

기준에 포함 +된 경우 주제의 해당 요소를로 바꿉니다 +.

⁼θη

주제와 기준을 비교하고 결과를 암시 적으로 인쇄합니다.


0

레티 나 0.8.2 , 42 바이트

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

온라인으로 사용해보십시오! 설명:

%`$
/

/두 줄 모두에 접미사 a 를 붙 입니다.

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

주제와 기준이 같거나 기준 요소가 (행복한) 동안 주제와 기준의 첫 번째 요소를 반복적으로 제거하십시오 +.

^¶$|¶#/$

기준은 그냥라면과 일치 #합니다 (로 /피사체와 기준, 그렇지 않으면 모두는이 시점에서 비어 있어야합니다 이전에 추가 된).






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.