Spójne nadziewanie bajtów (COBS)

10

Dziwię się, że nie zostało to wcześniej opublikowane!

Zgodnie bajtu narzutu Napełniacz (COB) algorytm jest stosowany do strumieni ograniczają bajtów.

Wybieramy znacznik ramki (użyjemy 0x00) i wszędzie tam, gdzie w strumieniu występuje 0x00, jest on zastępowany liczbą bajtów aż do następnego 0x00 (nazywamy to kamieniem milowym). Zmniejsza to zakres wartości od 0..255 do 1..255, umożliwiając 0x00 jednoznaczne wyznaczanie ramek w strumieniu.
W przypadku kamienia milowego, jeśli następne 255B nie będzie zawierało 0x00, przekroczy to maksymalną długość kamienia milowego - algorytm musi zatrzymać się na 255B i umieścić kolejny kamień milowy. Jest to „konsekwentny koszt ogólny”.
Pierwszy bajt będzie pierwszym kamieniem milowym, ostatnim kamieniem milowym będzie liczba bajtów do znacznika ramki.

Kilka przykładów z Wikipedii (najlepiej przeczytać artykuł, w którym są kolorowe):

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

Wyzwanie: wdrożyć to w najkrótszym programie.

  • Wejście to niekodowany strumień bajtów / tablica, wyjście to zakodowany strumień bajtów / tablica
  • Użyj dowolnego binarnego standardowego wejścia / wyjścia
  • Znacznik ostatniej klatki nie jest konieczny
  • Program może zwrócić ponadwymiarową tablicę
  • Strumień kończący się na 254 niezerowych bajtów nie wymaga końcowego 0x00

Notatki

  • Najgorsza długość zwrotu to numBytes + (numBytes / 254) + 1

Przykład

Mamy tablicę bajtów

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

Dla każdego z nich 0x00musimy określić (w kamieniu milowym), gdzie 0x00byłby następny .

[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.
Patrick
źródło
3
Prawdopodobnie powinieneś dołączyć to do specyfikacji: Jako specjalny wyjątek, jeśli pakiet kończy się grupą 254 bajtów niezerowych, nie jest konieczne dodawanie końcowego bajtu zerowego. To oszczędza jeden bajt w niektórych sytuacjach. (cytując Wikipedię)
Arnauld
3
@LuisMendo uzgodnione. Teraz, gdy przejrzałem wszystkie przypadki testowe, mogę potwierdzić, że jest to obecnie nieco nieokreślone.
Arnauld
@Arnauld, stwierdziłem, że końcowy producent ram i tak nie jest konieczny :)
Patrick
W tym przykładzie pierwszym bajtem wyjściowym powinien być 0x03, a nie 0x02, chyba że się mylę ...
Olivier Grégoire
1
@Arnauld w sprawie szczególnego przypadku zakończenia z 254 bajtami niezerowymi: zgódź się, a jest to osobny problem dla końcowego znacznika klatki. Dlatego szósty przykład nie ma końca, 01ale 01w dziewiątym są dwa s (gdzie jest 254 bajtów niezerowych, po których następuje zero).
Nick Kennedy,

Odpowiedzi:

2

Java (JDK) , 143 bajty

a->{int l=a.length,r[]=new int[l+2],i=0,j=1,x=1,z=0;for(;i<l;){if(a[i]>0)r[j++]=a[i];if(a[i++]<1||++x>254){r[z]=x;z=j++;x=1;}}r[z]=x;return r;}

Wypróbuj online!

Olivier Grégoire
źródło
1

Python 2 , 125 bajtów

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]

Wypróbuj online!

TFeld
źródło
1

Galaretka , 27 bajtów

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

Wypróbuj online!

Łącze monadyczne, które przyjmuje jako dane wejściowe niezakodowaną tablicę bajtów i zwraca zakodowaną tablicę bajtów. Zgodnie z regułami znacznik ostatniej klatki jest pomijany.

Wyjaśnienie

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
Nick Kennedy
źródło
1

Eliksir , 109 bajtów

&Regex.replace~r/(^|(?<=([^\0]{254}))(?!$)|\0)((?2)|[^\0]*?(?=\0|$))/,&1,fn _,_,_,x-><<1+byte_size x>><>x end

Wypróbuj online!

Kirill L.
źródło
0

J , 103 znaki

Zauważ, że wynik z ostatniego przypadku testowego różni się od wiki i innych języków. Wynika to z tego wskaźnika do 254-tego bajtu zerowego na granicy. Sprawa staje się znacznie łatwiejsza, jeśli nie jest to traktowane jako szczególny przypadek.

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

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

Wypróbuj online

Zhe Hu
źródło
Możesz go obniżyć o 1 bajt , usuwając końcowe spacje na końcu ostatniego wiersza.
ouflak