【问题标题】:String split on dynamic separator动态分隔符上的字符串拆分
【发布时间】:2019-04-04 18:11:54
【问题描述】:

我要处理以下问题。 我必须从通信缓冲区中提取消息。可悲的是,通信协议很糟糕,结构也不是很好。我想出的区分缓冲区中数据包的唯一方法是由服务器传输的中间“ack”命令。

示例:

[包1][ACK][包2][ACK][包3]

我可以使用 String.Split(ACK),但分隔符也不一致。不过,有 3 条规则可以识别 ack 数据包。

  1. 以“AK”开头。
  2. 以“0”或“1”结尾。
  3. 总长度为 5 个字符。

确认示例:
"AKxxy" 其中:
xx: (01 到 99)
y: (0 或 1)

我希望可能有一个正则表达式可以解决我的问题,但我缺乏所需的知识和时间。

是否有任何正则表达式“专家”可以帮助我?随时提出任何解决方案。
谢谢。

编辑:
示例数据包(我真的不得不删除数据包信息):
AK010机密包1AK011机密包2AK020AK011机密包3AK021机密包4AK050

遗憾的是,协议中的每个数据包都不是以特定字符开头或结尾的,所以我无法区分它们。为了识别每一个,我必须使用 ack 数据包将它们拆分,然后对每一个执行不同的检查。

【问题讨论】:

  • 您能否编辑问题并添加一些示例字符串和预期输出?
  • “但我缺乏所需的知识和时间。”这就是为什么你把你的工作交给我们?这不是 SO 应该如何工作的。我们都有自己的工作,时间不多。因此,如果您卡在某个特定点,请善待自己并提出问题。
  • @HimBromBeere 确实,我似乎将工作交给了其他人,但这不是我的目标。我认为对于一个对 RegEx 有深刻理解的人来帮助我将是一件容易的事。在过去的几天里,我一直在尝试使用复杂、丑陋且最终不正确的字符串操作来解决这个问题,但我做不到。如果我违反了任何社区政策,我深表歉意。
  • 更大的风险/问题是如果包裹可以跨越缓冲区的末端。

标签: c# regex string split packet


【解决方案1】:

直接翻译是

\bAK\d{2}[01]\b

那是

\b    # a word boundary
AK    # AK literally
\d{2} # two digits
[01]  # one of 0 or 1
\b    # another word boundary

但需要测试表达式(请参阅a demo on regex101.com)。

【讨论】:

  • 谢谢!有了这个表情,我似乎离我的目标很近了。您建议的确切表达方式没有给我任何结果。删除工作边界使我能够识别 ack 数据包。我对提供的表达式有进一步的工作。
  • 问题已解决。 var packets = Regex.Split(buffer, @"AK\d{2}[01]");
【解决方案2】:

编辑:

看看其他答案,这可能只是观赏价值。 @Jan 和@ThymosK 的解决方案

var packets = Regex.Split(buffer, @"AK\d{2}[01]");

看起来更优雅。

但我认为看看如何在正则表达式中移动所有解析可能会很好。即使它太难以理解:P

我设计了一个正则表达式,可以将消息和分隔符作为组提供:

(?s)(AK[0-9][0-9][0,1])|((?:(?!AK[0-9][0-9][0,1]).)*)

它可以像这样分析文本:

你可以测试一下here

像往常一样,正则表达式是只写的。我自己几乎看不懂这个。但我会尝试通过它:

第一组很简单,简单地捕获你的 ack 命令:

(AK[0-9][0-9][0,1])

第二组包含一个否定的前瞻(?! ... ),它与... 指定的正则表达式后面没有匹配的任何内容相匹配。在这里,我们插入您的 ack 语法,因此任何未跟随 ack 的内容都会匹配。然后我们添加一个字符,将其扩展为实际匹配到 ack 的任何内容。 基本上,第二部分断言我们当前没有跟随ack,然后添加一个字符。这会尽可能长时间地重复,直到我们找到ack。我把它变成第二组。

由于我目前没有 C#,因此无法使用 C# 正则表达式引擎将其封装在代码中。但是 python 可以很好地使用它,并提供了一个有用的 findall 方法,可以为您提供所有这些组。

【讨论】:

    【解决方案3】:
    string interim = Regex.Replace(buffer, "AK\d{2}[01]", "|");
    var commands = interim.Split('|');
    

    假设| 不是有效的输入字符。你可以选择一些非常奇特的东西。

    【讨论】:

    • 遗憾的是,大多数数据包都包含字符|,这样会给我带来更多麻烦。不过,我可以用我确定不会发送的序列替换 RegEx,然后用它拆分字符串。
    • 就像我说的:选择一些异国情调的东西。您可以使用任何 Unicode 字符,或者当它必须保持在 ASCII 范围内时,可以使用控制字符(Tab、Esc、...)
    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    相关资源
    最近更新 更多