Послідовне набивання накладних байтів (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 ненульових байтів, не потрібно додавати кінцевий нульовий байт. Це економить один байт у деяких ситуаціях. (цитуючи Вікіпедію)
Арнольд

3
@LuisMendo Погодився. Тепер, коли я пройшов усі тестові випадки, можу підтвердити, що наразі це трохи не визначено.
Арнольд

@Arnauld, я заявив, що виробник кінцевих кадрів все одно не потрібний :)
Патрік

У прикладі, перший вихідний байт повинен бути 0x03, а не 0x02, якщо я не помиляюся ...
Олів'є

1
@Arnauld щодо особливого випадку, що закінчується 254 ненульовими байтами: погодьтеся, і це окрема проблема остаточного маркера кадру. Ось чому шостий приклад не має трейлінгу, 01але 01в дев’ятому є два s (де 254 ненульових байти, а за ними нуль).
Нік Кеннеді

Відповіді:





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 символів

Зауважте, що результат останнього тестового випадку відрізняється від вікі та інших мов. Це пов'язано з цим вказівником на 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.