一致的开销字节填充(COBS)


10

令我惊讶的是,这还没有发布!

一致的开销字节填充(COBS)算法用于分隔字节流。

我们选择一个帧标记(我们将使用0x00),并且在流中出现0x00的任何地方都将其替换为字节数,直到下一个出现0x00为止(我们将其称为里程碑)。这将值的范围从0..255减小到1..255,从而使0x00可以明确地界定流中的帧。
在一个里程碑,如果下一个255B不包含0x00,则超出最大里程碑长度-算法必须“停顿”在255B并放置另一个里程碑。这是“一致的开销”。
第一个字节将是第一个里程碑,最后一个里程碑将是直到帧标记的字节数。

维基百科的一些示例(最好阅读彩色文章):

0x00 as frame marker

Unencoded data (hex)    Encoded with COBS (hex)
00                      01 01 00
00 00                   01 01 01 00
11 22 00 33             03 11 22 02 33 00
11 22 33 44             05 11 22 33 44 00
11 00 00 00             02 11 01 01 01 00
01 02 03 ... FD FE      FF 01 02 03 ... FD FE 00
00 01 02 ... FC FD FE   01 FF 01 02 ... FC FD FE 00
01 02 03 ... FD FE FF   FF 01 02 03 ... FD FE 02 FF 00
02 03 04 ... FE FF 00   FF 02 03 04 ... FE FF 01 01 00
03 04 05 ... FF 00 01   FE 03 04 05 ... FF 02 01 00

挑战:要在最短的程序中实现这一目标。

  • 输入是未编码的字节流/数组,输出是已编码的字节流/数组
  • 使用任何类型的二进制标准输入/输出
  • 最终帧标记不是必需的
  • 程序可以返回超大数组
  • 以254个非零字节结尾的流不需要尾随的0x00

笔记

  • 最坏情况下的返回长度是 numBytes + (numBytes / 254) + 1

我们有字节数组

[0] 0x01
[1] 0x02
[2] 0x00
[3] 0x03
[4] 0x04
[5] 0x05
[6] 0x00
[7] 0x06

对于每一个,0x00我们都需要(里程碑)说明下一个目标0x00

[0] 0x03   #Milestone. Refers to the original [2] - "The next 0x00 is in 3B"
[1] 0x01   #Original [0]
[2] 0x02   #Original [1]
[3] 0x04   #Milestone. Refers to the original [6] - "The next 0x00 is in 4B"
[4] 0x03   #
[5] 0x04   #
[6] 0x05   # Originals [3..5]
[7] 0x02   #Milestone. Refers to the end frame marker
[8] 0x06   #Original [7]
[9] 0x00   #Optional. End frame marker.

3
您可能应该将其包括在规范中:作为一个特殊的例外,如果数据包以254个非零字节为一组结束,则无需添加尾随零字节。在某些情况下,这样可以节省一个字节。(引用Wikipedia)
阿纳尔德

3
@LuisMendo同意。现在,我已经遍历了所有测试用例,现在可以确定这是个不足的地方。
阿纳尔德

@Arnauld,我已经说过最终框架制造商是没有必要的:)
Patrick

在示例中,第一个输出字节应该是0x03,而不是0x02,除非我弄错了...
OlivierGrégoire19年

1
@Arnauld关于以254个非零字节结尾的特殊情况:同意,这是最后一个帧标记的另一个问题。这就是为什么第六个示例没有结尾0101第九个示例中有两个s的原因(其中有254个非零字节,后跟一个零)。
肯尼迪

Answers:




1

Python 2,125个字节

def f(a):
 r=[[]]
 for v in a:r+=[[]]*((len(r[-1])>253)+(v<1));r[-1]+=[v]*(v>0)
 return sum([[len(x)+1]+x for x in r],[])+[0]

在线尝试!


1

果冻,27个字节

Oµ=0ks€254Ẏḟ€0L‘;Ɗ€F;Ṫ¬x`ƊỌ

在线尝试!

以未编码字节数组作为输入并返回编码字节数组的单子链接。根据规则,最后的帧标记将被省略。

说明

Oµ                          | Convert to integer and start a new monadic chain
  =0k                       | Split after zeros
     s€254                  | Split each list into length 254 lists
          Ẏ                 | Tighten (reduce list depth by 1)
           ḟ€0              | Filter zeros out from each list
              L‘;Ɗ€         | Prepend the list length plus one to each list
                   F        | Flatten
                    ;Ṫ¬x`Ɗ  | Append an additional 1 if the original list ended with zero
                          Ọ | Convert back to bytes


0

J,103个字符

请注意,最后一个测试用例的结果不同于Wiki和其他语言。这是由于该指针指向边界处的第254个零字节。如果这不是特例,事情会变得容易得多。

f =: 3 : 0
  k =. I. (y,0)=0
  s =. - 2 (-/) \ k
  (>: y i. 0), s (}:k) } y
 )

 f2 =: 3 : 0
   f each _254 <\ y
 )

在线试用


您可以通过删除最后一行末尾的尾随空格来将其降低1个字节
ouflak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.