Я разрабатываю небольшой интерпретатор сетевых команд для .net Micro Framework 4.3, работающий на Netduino. Я использую регулярное выражение для анализа пользовательского ввода, поступающего из сети через потоковый сокет. Команды имеют следующий формат:
<T1,0,CommandVerb=Payload>
Это адрес устройства, идентификатор транзакции, который может быть любым целым числом, команда, за которой следует знак равенства, за которым следует любой текст. Все это заключено в угловые скобки, очень похожие на тег 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+)|(.+)))?
различает числовую полезную нагрузку и текстовую полезную нагрузку или вообще никакой полезной нагрузки.
Это хорошо работает для меня и подтверждает OK в валидаторе регулярных выражений 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);
}
}
С тестовым вводом <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 [snip]
Я открыл проблему в отношении .NET MicroFramework.
((\d+)|(.+))
в(.+)
- person Avinash Raj   schedule 19.07.2015(=((\d+)|(.+)))?
является проблемой. Я все еще пытаюсь сузить круг. Это Group[4] доставляет мне проблемы, она пуста, когда я прихожу ее исследовать. - person Tim Long   schedule 19.07.2015OutOfRangeException
для этого индексатора — см. соответствующее обновление. - person Tim Long   schedule 19.07.2015