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 に対してイシューをオープンしました