【问题标题】:Using .NET Micro Framework, Why does my Regular Expression match fail?使用 .NET Micro Framework,为什么我的正则表达式匹配失败?
【发布时间】:2015-07-19 14:04:10
【问题描述】:

我正在为在 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 的正则表达式验证器中验证正常。这是我期望得到的输出(我认为这与您从完整的 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 作为有效负载传递。只要我的有效负载字符串中有一个点 (.),正则表达式就会中断,我实际上会返回第三种形式,它显然认为根本没有有效负载。举个例子:

<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] 为空,它为该索引器抛出一个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);
            }
        }

&lt;W1,0,HttpPost=http://deathstar.com&gt; 的测试输入输出为:

[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::子字符串 System.Text.RegularExpressions.Capture::get_Value TA.NetMF.WeatherServer.CommandParser::PrintMatches TA.NetMF.WeatherServer.CommandParser::ParseCommand [剪辑]

我有 opened an issue 反对 .NET MicroFramework

【问题讨论】:

  • 你为什么不把((\d+)|(.+))转成(.+)
  • 如果您发现了错误,或者您正在使用不受支持的正则表达式部分,请不要感到惊讶。不管怎样,你能把这个问题降到最低限度吗?你是说如果你有正则表达式 "(.+)" 它不会匹配 ".",还是你说如果你有 ((\d+)|(.+)) 它不会匹配 "." ?你的正则表达式对我来说似乎没问题。
  • 这似乎是整个最后一部分(=((\d+)|(.+)))? 这就是问题所在。我仍在努力缩小范围。是 Group[4] 给了我一个问题,当我来检查它时它是空的。
  • 我认为您可能是对的,这可能是一个错误。并不是 Group[4] 为空,而是为该索引器抛出了 OutOfRangeException - 请参阅有问题的更新
  • @AvinashRaj: »最后一部分 (=((\d+)|(.+)))?区分数字有效负载和文本有效负载,或者根本没有有效负载。«听起来对我来说很合适。

标签: c# regex .net-micro-framework netduino


【解决方案1】:

点匹配所有内容。 "(=((\d+)|(.+)))?>" 方法 1. 创建一个标记表达式(结尾的“?”表示它是可选的)。 2. 它必须以等号开头,并且包含 2.1。一个整数,或 2.2.任何东西,任何大小。

2.2 将匹配表达式的其余部分,无论它是什么。

然后,当匹配尾随的结束“>”时,如果“=”后面的不是整数,则缓冲区中没有任何内容。因此,没有匹配。

也许您可以在最后一部分尝试类似以下的内容:

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

【讨论】:

  • 嗯,.+ 默认不贪心吗?因此它应该只匹配下一个文字,不是吗?无论如何,在这个阶段我已经迫不及待地想要尝试任何东西,所以我确实尝试过,但它仍然失败(有趣的是它没有看到右尖括号)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
相关资源
最近更新 更多