我们的一个应用程序接收传感器发送的数据。通过检查消息的内容,应用程序必须确定它正在查看的消息类型以及传感器运行的固件版本。较新的固件版本发送额外数据,必须以不同方式处理。
我提供了以下示例,其中显示了不同版本的数据消息以及使用不同结构的配置消息。
您可以看到某些数据以逗号分隔,而某些数据则以新行分隔。消息中还有一些标记可用于确定消息类型。
鉴于我们无法更改消息结构并且消息未指示其固件版本,我正在寻找清晰,可维护,可扩展的解释数据方法的建议和示例。我们所能做的最好的就是尽可能优雅地处理事情。
旧版正常消息
[MSG]
4 031116 080423
543215432154321
3711mV
30
1,0,0
[READINGS]
00451,00450,00402,06017
00000,021116 083000
00000
00000
00000
00000,031116 080000
[MSGEND]
正常消息的较新版本
[MSG]
4 031116 080423
543215432154321
3711mV
30
1,0,0
**0000006216** <- Extra data added on extra line
[READINGS]
00451,00450,00402,06017
00000,021116 083000
00000
00000
00000
00000,031116 080000
[MSGEND]
配置报告
[MSG]
2 050416 194503
3913mV
30
1,1,0
0000006216
[CONFIG]
543215432154321
234,15,0037,01DE,-60,234,15,0037,42B0,-76
[MSGEND]
答案 0 :(得分:1)
看起来您的常规邮件格式为:
[MSG]
<one or more lines>
blank line
<one or more lines>
blank line
[SOME TEXT] // (i.e. [READINGS or CONFIG]
<one or more lines>
[MSGEND]
至少,您展示的三条消息具有通用格式。
我建议分阶段这样做。首先,收集数据,直到在缓冲区中获得完整的消息。也就是说,邮件以[MSG]
开头,以[MSGEND]
结尾。我将忽略通信失败或腐败的可能性,因为它并没有从根本上改变基本思想。 以某种方式将完整的消息发送到缓冲区。
现在你可以开始解析了。它看起来像消息的第一行(在[MSG]
之后)包含一些信息,您可以从中确定它是什么类型的消息。在您的示例中,正常消息在第一行以“4”开头,配置在第一行以“2”开头。
下一组线似乎提供特定类型的信息。如果您知道消息类型是什么,那么您就知道如何解释它。对于旧的和新的正常消息,您可以通过第五行的存在来判断它是什么类型的消息。
当然,[CONFIG]
或[READINGS]
之后的行会提供具体信息。
为消息处理创建通用模板应该非常简单:
Read "[MSG]"
Read identification information up to a blank line
Read blank line
Read more specific message information -- up to a blank line
Read blank line
Read line with "[CONFIG]" or "[READINGS]"
Read data lines up to "[MSGEND]"
Read "[MSGEND]"
如果您将这些数据行读入四个不同的列表,则可以检查数据并确定它是什么类型的消息。从那里,分支到特定的函数,用于解析和处理特定的消息类型。
你最终会重复一些代码,但是一旦你弄清楚这是否是你想要的处理方式,你总是可以抽象出来。
这当然是清晰和可维护的。它是否可扩展取决于您对可扩展性的定义。使用此模型,只要消息都采用相同的通用格式,您就可以轻松添加新类型的消息及其相应的处理方法。
我会提醒您不要尝试创建一个可以接收消息并将其拆分为相关部分的正则表达式。有足够的疑惑,你可以创建这样的正则表达式。可以肯定的是,大多数情况下,正则表达式几乎是不可读的,难以修改并证明是正确的,并且可能对格式偏差很不宽容。
答案 1 :(得分:0)
我认为如果你分析一个足够大的消息样本(例如100),你会发现一个模式。携带传感器读数的非结构化消息非常罕见。
一旦确定,您可能会发现按类型匹配消息最简单,最干净(例如,数据消息和配置,基于您的示例)。例如,此正则表达式将匹配您的“旧/旧”OR新消息,但不匹配配置消息。如果消息是“新”,则将有2个捕获组 - 第一个具有10位固件,第二个具有数据(传感器读数)。如果消息是“old / legacy”,则正则表达式将只包含1个捕获组,并带有传感器读数:
^\[MSG\]\n[\d ]+\n{2}\d{15}\n\d{4}mV\n\d{2}\n\d,\d,\d\n?\*{0,2}(\d{10})?\*{0,2}\n{2}\[READINGS\]\n(?m:([\d\s,]*))\[MSGEND\]$
当然,我的例子只是 - 一个例子 - 它需要更多数据进行验证,更多捕获组来确定传感器类型等;但这就是我如何解决你的问题。
正则表达资源:
这是regex101.com上此正则表达式的link。
我也非常喜欢regexper.com用于正则表达式的可视化(它们比读取更容易编写,imho)。这是正则表达式visualized。
注意,我从数据捕获组的可视化中删除了多行标记 - (?m:
。这不是绝对必要的。