2

Netduino で実行されている .net Micro Framework 4.3 用の小さなネットワーク コマンド インタープリターを開発しています。正規表現を使用して、ストリーム ソケット経由でネットワークから届くユーザー入力を解析します。コマンドの形式は次のとおりです。

<T1,0,CommandVerb=Payload>

これは、デバイス アドレス、任意の整数のトランザクション ID、コマンド動詞、それに続く等号と任意のテキストです。全体が XML タグのように山かっこで区切られているため、解析に役立ちます。

私が使用する正規表現は次のとおりです。

    /*
     * Regex matches command strings in format "<Dn,TT,CommandVerb=Payload>
     * D is the Device class
     * n is the device index
     * TT is a numeric transaction ID of at least 1 digits.
     * CommandVerb is, obviously, the command verb ;-)
     * Payload is optional and is used to supply any parameter values to the command.
     * 
     * N.B. Micro Framework doesn't support named captures and will throw exceptions if they are used.
     */

    const string CommandRegex = @"<(\w\d),(\d+),([A-Za-z]\w+)(=((\d+)|(.+)))?>";
    static readonly Regex Parser = new Regex(CommandRegex);

この式は、コード内で簡単にアクセスできるように、コマンドのさまざまな部分を引き出すように設計されています。最後の部分(=((\d+)|(.+)))?は、数値ペイロードとテキスト ペイロードを区別するか、ペイロードをまったく区別しません。

これは私にとってはうまく機能しており、ReSharper の正規表現バリデーターで OK を検証します。これが私が期待する出力です (これは完全な NetFX から得られる結果とは微妙に異なると思います。試行錯誤してこれを解決する必要がありました):

        /* Command with numeric payload has the following groups
         * Group[0] contains [<F1,234,Move=12345>]
         * Group[1] contains [F1]
         * Group[2] contains [234]
         * Group[3] contains [Move]
         * Group[4] contains [=12345]
         * Group[5] contains [12345]
         * Group[6] contains [12345]  
         * -----
         * Command with text payload has the following groups:
         * Group[0] contains [<F1,234,Nickname=Fred>]
         * Group[1] contains [F1]
         * Group[2] contains [234]
         * Group[3] contains [Nickname]
         * Group[4] contains [=Fred]
         * Group[5] contains [Fred]
         * Group[7] contains [Fred]
         * -----
         * Command with verb only (no payload) produces these groups:
         * Group[0] contains [<F1,234,Stop>]
         * Group[1] contains [F1]
         * Group[2] contains [234]
         * Group[3] contains [Stop]
         */

...そして、それはそのように機能します。URLをペイロードとして渡そうとしたところまで。ペイロード文字列にドット (.) があるとすぐに、正規表現が壊れて、実際には 3 番目の形式に戻ります。ここでは、明らかにペイロードがまったくないと考えられます。例として:

<W1,0,HttpPost=http://deathstar.com/route>

返されると期待しているのは「テキスト ペイロードを含むコマンド」の結果ですが、実際に返されるのは「ペイロードのないコマンド」の結果です。ドットを取り出すと、期待どおりに解析され、「テキスト ペイロードを含むコマンド」が得られます。ドットを元に戻すとすぐに、(皮肉なことに).+一致しなくなったようです。

繰り返しますが、これは ReSharper の正規表現バリデーターで正しく検証され、通常の「デスクトップ」フレームワークでは期待どおりに動作するように見えますが、.NET Micro Framework では動作しません。Micro Framework 正規表現の実装はフル バージョンのサブセットですが、何が機能し、何が機能しないかに関するドキュメントはほとんど存在しません。

.+ドットが含まれるテキストと一致しない理由がわかりません。なぜ機能しないのか誰にもわかりますか?

更新 1 - 追加された診断

出力は次のとおりです。

[Cmd Processor     ] Parser matched 8 groups
[Cmd Processor     ]   Group[0]: <W1,0,HttpPost=http://deat
[Cmd Processor     ]   Group[1]: W1
[Cmd Processor     ]   Group[2]: 0
[Cmd Processor     ]   Group[3]: HttpPost
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll

したがって、Group[4]null ではなくArgumentOutOfRangeException、8 つのグループがあるにもかかわらず、そのインデクサーに対して をスローしています。また、Group[0]不思議なことに切り詰められています。うーん...

更新 2 - 診断の改善

@ Shar1er80 からの回答に基づいて、この診断方法をコードに追加しました。

    [Conditional("DEBUG")]
    static void PrintMatches(Match match)
        {
        if (!match.Success)
            {
            Dbg.Trace("No match", Source.CommandProcessor);
            return;
            }
        Dbg.Trace("Parser matched "+match.Groups.Count + " groups", Source.CommandProcessor);
        for (int i = 0; i < match.Groups.Count; i++)
            {
            string value;
            try
                {
                var group = match.Groups[i];
                value = group == null ? "null group" : group.Value ?? "null value";
                }
            catch (Exception ex)
                {
                value = "threw " + ex.GetType() + " " + ex.Message??string.Empty;
                }
            Dbg.Trace("  Groups[" + i + "]: " + value, Source.CommandProcessor);
            }
        }

出力のテスト入力<W1,0,HttpPost=http://deathstar.com>は次のとおりです。

[Cmd Processor     ] Parser matched 8 groups
[Cmd Processor     ]   Groups[0]: <W1,0,HttpPost=http://deaths
[Cmd Processor     ]   Groups[1]: W1
[Cmd Processor     ]   Groups[2]: 0
[Cmd Processor     ]   Groups[3]: HttpPost
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
[Cmd Processor     ]   Groups[4]: threw System.ArgumentOutOfRangeException Exception was thrown: System.ArgumentOutOfRangeException
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
[Cmd Processor     ]   Groups[5]: threw System.ArgumentOutOfRangeException Exception was thrown: System.ArgumentOutOfRangeException
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
[Cmd Processor     ]   Groups[6]: threw System.ArgumentOutOfRangeException Exception was thrown: System.ArgumentOutOfRangeException
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
[Cmd Processor     ]   Groups[7]: threw System.ArgumentOutOfRangeException Exception was thrown: System.ArgumentOutOfRangeException
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll

8 件の一致が報告されていますが、Groups[3] に関する何かにアクセスしようとすると例外がスローされるため、これは明らかに正しくありません。例外のスタック トレースは次のとおりです。 System.String::Substring System.Text.RegularExpressions.Capture::get_Value TA.NetMF.WeatherServer.CommandParser::PrintMatches TA.NetMF.WeatherServer.CommandParser::ParseCommand [省略]

.NET MicroFramework に対してイシューをオープンしました

4

1 に答える 1

1

ドットはすべてに一致します。"(=((\d+)|(.+)))?>" は 1 を意味します。タグ付き式を作成します (末尾の '?' はオプションであることを意味します)。2. 等号で始まり、2.1 のいずれかを含む必要があります。整数、または 2.2。何でも、どんなサイズでも。

2.2 は、それが何であれ、式の残りの部分に一致します。

その後、末尾の「>」に一致する時が来て、「=」の後に続くものが整数でない場合、バッファには何も残っていません。したがって、一致しません。

おそらく、最後の部分では、代わりに次のようなことを試すことができます。

"(=([^>]+))?>".

于 2015-07-19T15:05:42.980 に答える