MQTTサブスクリプショントピックの一致


10

バックグラウンド

MQTT(メッセージキューテレメトリトランスポート)は、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 / firstfloor /リビング/温度
ガレージ /地上階/ 冷蔵庫 /気温

サブスクリプション+/groundfloor/#がこれらの結果を生成するのに対し、

✅myhome / groundfloor / livingroom / temperature✅myhome
/ groundfloor / kitchen / brightness✅garage
/ groundfloor / fridge / temperature / more / specific /
fields❌myhome / firstfloor / livingroom / temperature❌myhome
/ basement / corner /気温

詳細はこちら

タスク

2つの文字列を受け入れ、ブール値を返す関数/プログラムを実装します。最初の文字列はサブジェクトトピックで、2番目の文字列は基準トピックです。基準トピックでは、上記のサブスクリプション構文を使用します。サブジェクトが基準に一致する場合、関数は真実です。

このタスクのルール:

  • トピックはASCIIです
  • #ワイルドカード以外の基準フィールドはありません
  • ワイルドカードは件名のトピックに表示されません
  • 件名フィールドの数> =基準フィールドの数
  • 0文字のフィールドも、スラッシュの先頭または末尾にもありません。

テストケース

条件1 = "myhome / groundfloor / + / temperature"
条件2 = "+ / 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
( "ガレージ/グラウンドフロア/冷蔵庫/温度"、基準1)=> false
( "マイホーム/グラウンドフロア/リビングルーム/温度"、基準2)=> true
( "マイホーム/グラウンドフロア/キッチン/明るさ"、基準2)=> true
(「ガレージ/グラウンドフロア/冷蔵庫/温度/詳細/特定/フィールド "、基準2)=> true
(" myhome / firstfloor / livingroom / temperature "、基準2)=> false
( "myhome / basement / corner / temperature"、criteria2)=> false
( "music / kei $ ha / latest"、 "+ / kei $ ha / +")=> true


@HyperNeutrino、それは良い質問です。私はフェンスの上にいます。件名a/b/cは条件a/bに一致しないため、「いいえ」と言う傾向があります。
Patrick

4
/、+、および#がトピック部分に表示されないことが保証されていますか?
ジョナサンアラン

「さらにスラッシュだけでも有効なトピックである」とリンクされているブログで、+と#について言及していないので、これら2つは可能だと思います。
ジョナサンアラン

1
@JonathanAllanから Fromdocs.oasis-open.org/mqtt/mqtt/v3.1.1/os/…:ワイルドカード文字はトピックフィルターで使用できますが、トピック名内では使用できません
Nick Kennedy

2
@NickKennedy-いい掘りですが、実際にそうする必要はありません。
ジョナサンアラン

回答:


3

ゼリー、20バイト

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

文字リストのリストを受け入れるモナディックリンク[topic, pattern]。これは10それぞれ一致するか一致しないかを返します。

オンラインでお試しください!またはテストスイートをご覧ください。

どうやって?

ṣ€”/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.escape基準名がたまたまcom.java/string[]/\n正規表現の断片を持つような、または愚かなものである場合に備えて、私は追加しました。

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

オンラインでお試しください!

非正規表現ソリューション、77バイト

シンプルな分割、zip、および一致のテクニックを使用しています。私はこれを最初に開発してから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バイト長くなります。しかたがない。
モニカの訴訟に資金


1

Python 3、72バイト

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

オンラインでお試しください!

この問題は簡単に正規表現一致に簡略化できますが、より興味深い別の方法でより良い結果が得られる場合があります。

編集私は正規表現を使用しない107バイトのソリューションを思いつきました。72より短くなるかどうかはわかりませんが、おそらくこれに対する正しいアプローチを見ていません。ただし、分割zip構造だけでは大きすぎるようです。オンラインでお試しください!


2
シーケンスに他の正規表現文字が含まれている場合、これは失敗する可能性があります。現在のテストケースにはリモート正規表現のようなものは含まれていませんが、私はそれを探します。
バリューインク

... f('myhome/ground$floor/livingroom/temperature', 'myhome/ground$floor/+/temperature')失敗したように
ジョナサンアラン

Value Inkが言うように、+/kei$ha/+は一致しませんmusic/kei$ha/latest
Chas Brown

1

パイソン285の 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')ます。
バリューインク

@ジョナサン・アラン:実際、ルールは「件名フィールドの数> =基準フィールドの数」と言っています。しかし、他の問題を修正する必要がありました
Chas Brown

問題のコンテキストが与えられたああ奇妙なルール!
ジョナサンアラン

1

Haskell、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

Python 3、99 88バイト

正規表現を使用せずに。ジョナサンアランとチャスブラウンの助けを借りて。

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バイトのコストで指摘しました。
ジョナサンアラン

末尾の「+」(例:)の別のエッジケースに失敗しf('a/b', 'a/+')ますが、0バイトで修正できます...or(s[:1]in'/')*2:])
ジョナサンアラン

常にオンライン試すことをお勧めします!
Chas Brown

0

チャコール、36バイト

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

オンラインでお試しください!リンクはコードの詳細バージョンです。一致-の出力(炭の暗黙の出力true)。一致がない場合は何も出力されません。説明:

≔⪪S/θ

件名を/sに分割します。

≔⪪S/η

基準を/sに分割します。

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

基準にaが含まれている(つまり、末尾がaである)場合は、基準を#削除し、基準を基準の新しい長さにトリミングします。

F⌕Aη+§≔θι+

基準に含まれる+場合、件名のその要素をに置き換え+ます。

⁼θη

主題と基準を比較し、結果を暗黙的に出力します。


0

Retina 0.8.2バイト

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

オンラインでお試しください!説明:

%`$
/

接尾辞a /両方の行の。

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

サブジェクトと基準の両方の最初の要素を繰り返し削除します。 +ます。

^¶$|¶#/$

条件がちょうどaである場合#/以前に追加された)と一致します。それ以外の場合は、この時点で件名と条件の両方が空になります。






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.