Телеграфия в гольф: расшифровка кода Бодо


31

Задний план

В 1870 году Эмиль Бодо изобрел код Бодо , кодировку символов фиксированной длины для телеграфии. Он разработал код для ввода с ручной клавиатуры всего пятью клавишами; два оперированы левой рукой и три - правой:

Бодо 5-клавишная клавиатура

Правый указательный, средний и безымянный пальцы управляют клавишами I , II и III соответственно, а левый указательный и средний пальцы управляют IV и . (Отныне я буду использовать их западно-арабские цифры, то есть от 1 до 5. ) Символы вводятся как аккорды. Например, для ввода буквы «С» оператор нажимает 1 , 3 и 4.одновременно с клавишами, после чего вращающийся рычаг щетки считывает каждую клавишу последовательно и передает ток или, если клавиши не нажаты, тока нет. В современных терминах результатом является двоичное кодирование с 5-разрядным наименее значимым разрядом-первым, в котором наш пример, "C", кодируется как 10110.

5 бит

Вы можете подумать, что 5 битов, которые могут выражать не более 32 уникальных символов, недостаточно даже для всех английских букв и цифр, не говоря уже о пунктуации. Однако у Бодо была хитрость: его набор символов на самом деле состоит из двух разных наборов: букв и цифр , и он определил два специальных кода для переключения между ними. Сдвиг букв , который переключается в режим букв, активируется нажатием одной клавиши 5 ( 00001), а смещение цифр активируется клавишей 4 ( 00010).

Вызов

Ваша задача - написать программу или функцию, которая декодирует передачи кода Бодо.

Реальная передача будет начинаться с некоторых битов инициализации, плюс биты начала и остановки до и после каждого символа, но мы собираемся пропустить их и беспокоиться только о 5 уникальных битах для каждого символа. Форматы ввода и вывода обсуждаются ниже.

Код Бодо

Существует две разные версии кода Baudot: Continental и UK. Мы собираемся использовать версию для Великобритании, которая не включает символы типа «É» из французского языка Baudot. Мы также собираемся исключить все символы в британской версии, которые не входят в число печатных символов ASCII. Вам нужно будет только декодировать символы в таблице ниже, все из которых являются печатными символами ASCII, за исключением последних трех управляющих символов, которые объяснены под таблицей.

В столбце «Ltr» отображаются символы в режиме «Letter», а в «Fig» - символы режима «Figure»:

        Encoding             Encoding
Ltr Fig  12345       Ltr Fig  12345
--- --- --------     --- --- --------
 A   1   10000        P   +   11111
 B   8   00110        Q   /   10111
 C   9   10110        R   -   00111
 D   0   11110        S       00101
 E   2   01000        T       10101
 F       01110        U   4   10100
 G   7   01010        V   '   11101
 H       11010        W   ?   01101
 I       01100        X       01001
 J   6   10010        Y   3   00100
 K   (   10011        Z   :   11001
 L   =   11011        -   .   10001
 M   )   01011        ER  ER  00011
 N       01111        FS  SP  00010
 O   5   11100        SP  LS  00001
 /       11000

Последние три строки в правом столбце являются управляющими символами:

  • ERэто Erasure . Телеграфные машины Бодо будут печатать символ, похожий на звездочку, для этого символа, чтобы сказать читателю, что предыдущий символ следует игнорировать, но мы собираемся быть еще более приятным для читателя и фактически опустим (не печатаем) предыдущий символ . Он действует одинаково как в буквенном, так и в графическом режиме.

  • FSэто сдвиг фигуры . Это переключает набор символов с букв на цифры. Если декодер уже находится в режиме ввода рисунков, FS рассматривается как пробел (следовательно, SPв столбце «Ltr»). Когда декодер находится в режиме «Рисунок», он остается в режиме «Рисунок», пока не будет получен символ LS.

  • LSэто письмо сдвига . Он переключает набор символов с цифр на буквы. Если декодер уже находится в режиме Letter, LS рассматривается как пробел . В режиме Letter декодер остается в режиме Letter до получения символа FS.

Декодер всегда запускается в режиме Letter.

Вот пример с Figure Shift, Letter Shift и Space:

01011 10000 00100 00001 00010 10000 11100 00001 10101 11010
  M     A     Y   LS/SP FS/SP   1     5   LS/SP   T     H

Это дает сообщение MAY 15TH. Как вы можете видеть, первый 00001(Letter Shift / Space) символ действует как пробел, потому что декодер уже находится в режиме Letter. Следующий символ 00010(Figure Shift / Space) переключает декодер в режим Figure для печати 15. Затем 00001снова появляется, но на этот раз он действует как Letter Shift для перевода декодера обратно в режим Letter.

Для вашего удобства, вот символы в формате, который, возможно, легче переварить в редакторе, отсортированный по коду:

A,1,10000|E,2,01000|/,,11000|Y,3,00100|U,4,10100|I,,01100|O,5,11100|FS,SP,00010|J,6,10010|G,7,01010|H,,11010|B,8,00110|C,9,10110|F,,01110|D,0,11110|SP,LS,00001|-,.,10001|X,,01001|Z,:,11001|S,,00101|T,,10101|W,?,01101|V,',11101|ER,ER,00011|K,(,10011|M,),01011|L,=,11011|R,-,00111|Q,/,10111|N,,01111|P,+,11111

вход

Входными данными будут строка, массив или список битов в порядке младших битов в первом порядке. Каждый символ будет представлен квинтетом из 5 бит. Биты могут быть в любом подходящем формате, например , двоичную строку, массив 0с и 1с, строки "0"и "1" символов, один очень большое количество, и т.д., до тех пор , как он отображает непосредственно битам передачи.

Каждая передача будет иметь, по крайней мере, один печатный квинтет и не более 255 квинтетов (для печати или иным образом), т.е. 5–1275 бит включительно.

Входные данные могут содержать только биты передачи, с двумя допустимыми исключениями: любое количество начальных или конечных 0битов и / или, для ввода строки, одна конечная новая строка может быть добавлена ​​к передаче. Начальные или конечные биты или символы не могут быть добавлены до или после каждого квинтета, т. Е. Вы не можете дополнить каждый квинтет до 8 бит (или принять каждый квинтет как одно число в массиве - если у вашего языка нет 5-битного целочисленного типа) или отдельно квинтеты с любыми дополнительными битами, например "01111\n11100".

Примечания и крайние случаи

  1. Передача будет содержать только символы в столбцах «Ltr» и «Fig» в таблице выше. Вы никогда не получите, например, 01110в режиме рисунка, потому что он отсутствует в столбце «Рис».

  2. Предполагается, что декодер всегда будет в режиме Letter в начале передачи. Тем не менее, первый символ может быть символом FS для немедленного переключения в режим рисунка.

  3. Когда декодер находится в режиме Letter, он может получить символ LS, а когда он находится в режиме Figure, он может получить символ FS. В любом случае символ пробела должен быть напечатан (см. Вывод).

  4. Символ ER никогда не будет первым символом в передаче, и он никогда не будет сразу следовать за LS, FS или другим ER.

  5. Символ FS может сразу следовать за символом LS и наоборот.

  6. Ни символы LS, ни FS не будут последним символом в любой передаче.

  7. /И -символы могут быть получены в любом режиме Letter (кодов 11000и 10001, соответственно) или в режиме (рис 10111 и 00111).

Выход

Выходные данные могут быть в любом приемлемом формате, наиболее приемлемым из которых является ASCII (или UTF-8, для которого все представленные символы совпадают с ASCII). Пожалуйста, укажите в своем ответе, если ваш вывод в другой кодировке или формате.

Заметки

  • Пробел (см. 3. выше) должен быть пробелом ASCII (0x20) или эквивалентом вашей кодировки, то есть тем, что вы получаете, когда нажимаете клавишу пробела.

выигрыш

Это . Самый короткий код в байтах побеждает.

ограничения

  • Стандартные лазейки запрещены.

  • Допускаются завершающие пробелы и / или одиночный завершающий перевод строки. Пробелы или другие символы (которые не являются частью передачи) запрещены.

  • Вы не можете использовать какие-либо встроенные или библиотечные функции, которые декодируют код Бодо (или любого из его потомков, например, код Мюррея, ITA-1 и т. Д.).

Тестовые случаи

Input: 001101000010100111101110010101
Output: BAUDOT
Input: 11010010001001100011110111101111100
Output: HELLO
Input: 01011100000010000001000101000011100000011010111010
Output: MAY 15TH
Input: 0001000100010000001000001011101110011100101010010110101010001111100101
Output: 32 FOOTSTEPS
Input: 10110000110101011100111100001111011010000001101110
Output: GOLF
Input: 000100011000001111100000100010110111001100010110010000111111
Output: 8D =( :P
Input: 0000100001000010000100010001111011111011000011100010001
Output (4 leading spaces):     -/=/-


1
Примечание: я закодировал тестовые случаи вручную; если вы видите что-то, что выглядит неправильно, пожалуйста, говорите.
Джордан,

1
В таблице кодов и сопроводительном дайджесте код 00010указан как SPв буквенном режиме, так и FSв графическом режиме. Согласно описанию, если мы находимся в буквенном режиме и получаем код 00010, мы должны перейти в режим ввода цифр, но значения в таблице, кажется, наоборот. Также наоборот для 00001.
Сок

3
Этот человек был чертовски умным, я никогда не знал о сжатии, используемом в телеграфии. Спасибо за урок истории человеку.
Волшебная Урна Осьминога

4
@carusocomputing Право ?? У Бодо не было формального образования, кроме начальной школы, но он не только изобрел код Бодо, он изобрел систему мультиплексирования, которая позволяла четырем операторам одновременно использовать одну телеграфную линию. Я нашел эту брошюру 1919 года, которая описывает его изобретения в некоторых деталях, очень интересной: samhallas.co.uk/repository/telegraph/b6_baudot_multiplex.pdf
Иордания,

Ответы:


6

Pyth, 98 97 95 93 90 83 80 байт

Код содержит непечатаемые символы, так что вот обратимый xxdhexdump:

00000000: 753f 7133 4a69 4832 5047 2b47 3f3c 334a  u?q3JiH2PG+G?<3J
00000010: 4040 6332 2e22 275a 75ae 5751 fb4e 3cd7  @@c2."'Zu.WQ.N<.
00000020: 02ce 8719 aac1 e0e0 fe1f 09e5 85bc a767  ...............g
00000030: 8e0c 1f47 508a cad1 1acb b26f 951e e5d6  ...GP......o....
00000040: 225a 4a2a 5c20 715a 3d5a 744a 637a 356b  "ZJ*\ qZ=ZtJcz5k

Попробуйте онлайн. Тестирование.

Довольно долго, но справочная таблица занимает большую часть пространства.

Для 117 байтов то же самое без непечатаемых (хотя требуется ISO-8859-1):

u?q3JiH2PG+G?<3J@@c2."'Zu®WQûN<×\x02Î\x87\x19ªÁààþ\x1f\tå\x85¼§g\x8e\x0c\x1fGP\x8aÊÑ\x1a˲o\x95\x1eåÖ"ZJ*\ qZ=ZtJcz5k

Или, для 93 байтов, без сжатия в таблице поиска:

u?q3JiH2PG+G?<3J@@c2"OVDPYSBREXGMIWFNA-JKUTCQ/ZHL5'0+3;8-2;7);?;;1.6(4;9/;:;="ZJ*\ qZ=ZtJcz5k

5

JavaScript (ES6), 160 158 153 байта

let f =
    
s=>s.replace(/.{5}/g,s=>(n='0b'+s-1)<2?m-n?(m^=1,''):' ':"? !YSBREXGMIWFNA-JKUTCQ/ZHLOVDP? ?!3 8-2 7) ?  1.6(4 9/ : =5'0+"[n+m*32],m=0).replace(/.!/g,'')

console.log(f("001101000010100111101110010101"));
console.log(f("11010010001001100011110111101111100"));
console.log(f("01011100000010000001000101000011100000011010111010"));
console.log(f("0001000100010000001000001011101110011100101010010110101010001111100101"));
console.log(f("10110000110101011100111100001111011010000001101110"));
console.log(f("000100011000001111100000100010110111001100010110010000111111"));
console.log(f("0000100001000010000100010001111011111011000011100010001"));


5

Пакет, 306 304 байта

@echo off
set/pc=
set r=
set d=! !!YSBREXGMIWFNA-JKUTCQ/ZHLOVDP!! !3!8-2!7)!?!!1.6(4!9/!:!=5'0+
set s=2
:l
set/an=(s^&32)+0%c:~,2%%%6*8+0x%c:~2,3%%%14
set c=%c:~5%
if %n%==%s% set/as^^=35&goto l
call set r=%%r%%%%d:~%n%,1%%
if %r:~-1%==! set r=%r:~,-2%&goto l
if not "%c%"=="" goto l
echo %r%

Принимает участие в STDIN. Поскольку Batch не имеет двоичного преобразования, я должен подделать его, используя восьмеричное и шестнадцатеричное преобразование.

  • Первые две цифры преобразуются из восьмеричного (я не могу использовать десятичную, потому что первая цифра может быть 0). Возможные значения 00, 01, 10и 11. Последние два имеют значение 8и , 9но я хочу , 2или 3так я взять остаток по модулю 6.
  • Последние три цифры преобразуются из шестнадцатеричного. Цифры либо либо, 14либо 252умноженные на их желаемое значение, чтобы я взял остаток по модулю 14( 252=14*18).
  • c это закодированная строка
  • r пока результат
  • d это массив декодирования
  • s является индексом (с учетом состояния сдвига) символа, который переключает состояние сдвига
  • nэто двоичное декодирование плюс бит 5 s, который либо равен состоянию сдвига, в этом случае состояние сдвига переключается, либо индексирует в массив декодирования, чтобы найти следующий символ (или! для удаления)

3

PHP, 206 байт

foreach(str_split($argv[1],5)as$s)($k="# f*YSBREXGMIWFNA-JKUTCQ/ZHLOVDP#l *3#8-2#7)#?##1.6(4#9/#:#=5'0+"[32*$f+bindec($s)])=="*"?array_pop($a):($k=="f"?$f=1:($k=="l"?$f=0:($k=="#"?:$a[]=$k)));echo join($a);

2

Чип , 1069 байт

Это большое дело, но писать было довольно весело.

Принимает ввод в виде строки "1"'s и "0"'. (Хотя это действительно только смотрит на младший бит.)

 AZZZZ,-o.AZZZZ  AZZZZ,o-.AZZZZ
*\\\\\]oo[\/\\\**//\\\]oo[/\\\\*
*\\\\/]oo[\/\\/**//\\/]oo[/\\\/*
*\\\//]oo[\/\//**//\//]oo[/\\//*
*\\\/\]oo[\/\/\**//\/\]oo[/\\/\*
*\\//\]oo[\///\**////\]oo[/\//\*
*\\///]oo[\////**/////]oo[/\///*
*\\/\/]oo[\//\/**///\/]oo[/\/\/*
*\\/\\]oo[\//\\**///\\]oo[/\/\\*
=
        o--------K-----o
      ,oo.   z---+~S  ,oo.
     ,LooR. !ZZZZ'   ,LooR.
    ,LLooRR.        ,LLooRR.
   ,LLLooRRR.      ,LLLooRRR.
  ,LLLLooRRRR.    ,LLLLooRRRR.
 ,LLLLLooRRRRR.  ,LLLLLooRRRRR. ,~Z
,LLLLLLooRRRRRR.,LLLLLLooRRRRRR.>m'
|||||||oo||||||||||||||oo||||||)/Rz.
xxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxx\^-^S
x)x))))))))))))xx)))))))))))))xx\g
xx)xxxxxxxxxxxxxxxxxxxxxxxxxxx))\f
xxxxxx))xxxxxxxxxxxxx)))))))))xx\e
xx)x))x)xxxxx))x)))))xxxxxxx)))x\d
xx))x))xxx)))xxxxx)))xxxx)))xx)x\c
xx)xx)xx))x))x)xx)xx)xx))x))x)xx\b
x)))))))x)xx)xxxx)x)xx)x)xx)xx)x\a
x)x)x))))))x)x))x)))x)))xx))x))x/f
x)x)x))))))x)x)xxx)xxxxxxxx)x)xx/e
xxxxxxxx))xxxxxx))))x)))xxx)x))x/d
xxxxx))xxxxx)x)xxx)xxx))xx))xx)x/c
xxx)xxx)xxxx)x)xxxxxx))xxx))x))x/b
x)xxx)x)x)xx)xxxxx))x)))xx))xxxx/a

Попробуйте онлайн!

Примечание: Erasure использует символ возврата ASCII ( \x08), что означает, что они будут выглядеть забавно в TIO, но они хорошо выглядят, скажем, в xterm.

Базовая структура

Вверху, над =линией, находится входной декодер. Превращает вход в один из 32 отдельных сигналов. Они отправляются от oвыше =к тем ниже.

Треугольные горы L's' и R's' просто вращают шаблон из отдельных строк в столбцы. Сетка ниже, которая переводит каждый столбец в его выходной символ. Для неизвестных сигналов выдается NUL ( \x00). Для специальных сдвигов вместо печати символа маленький шарик вправо меняет режим.

Канатная дорога между двумя горами подавляет любую печать между каждым квинтетом, в противном случае это также попыталось бы декодировать все перекрывающиеся квинтеты. Попробуйте заменить !его пробелом, чтобы убедиться в этом. (Запуск в подробном режиме -vтакже может быть интересным здесь.)

Я не уверен, как сделать это меньше в данный момент; это уже довольно плотно для его размера.


0

GNU sed, 334 + 1 = 335 байтов

+1 байт за -rфлаг. Принимает участие в STDIN.

Просматривая старые проблемы, я понял, что это будет довольно легко с sed, и хорошо для практики. Я не пытался выполнить какое-либо сжатие, поэтому таблица поиска составляет более половины кода.

s|.*|#@&;01000E211000/%00100Y310100U401100I%11100O500010f 10010J601010G711010H%00110B810110C901110F%00001 l10001-.01001X%11001Z:00101S%10101T%01101W?11101V'00011<<10011K(01011M)11011L=00111R-10111Q/01111N%11111P+10000A111110D0|
:
s/@([01]{5})(.*;.*\1)(..)/\3@\2\3/
t
s/@;.*//
s/#f /@/
s/@ l/#/
s/#(.)./\1#/
s/@.(.)/\1@/
t
s/.<|[#@]//g

Попробуйте онлайн!

объяснение

Код работает в два этапа: во-первых, он заменяет каждый набор из 5 двоичных цифр соответствующими двумя символами (буква и цифра) из справочной таблицы. Таблица поиска имеет формат 𝟎𝟎𝟎𝟎𝟎𝐋𝐅𝟎𝟎𝟎𝟎𝟎𝐋𝐅… где 𝟎 - двоичная цифра, а 𝐋 и 𝐅 - соответствующая буква и цифра соответственно. %заменяет отсутствующие символы (это может быть любой символ, кроме новой строки). FS/SPпредставлен f<space>и SP/LSесть <space>l. ERпредставлен <<.

Затем он проходит по каждой паре с «курсором», соответствующим текущему #режиму - для буквенного режима, @для режима фигуры. #Курсор удаляет второй символ из пары , а затем переходит к следующей паре, и @удаляет первый и достижения. Другими словами, #A1B8становится A#B8и тогда AB#, и @A1B8становится 1@B8и тогда 18@. Когда #курсор встречается, f<space>он удаляет его и заменяет собой @курсор, и наоборот, когда @встречает <space>l.

Если пар не осталось, последний курсор удаляется вместе с любыми символами, за которыми следует <.

# Setup: Append a lookup table to the line.
# Also prepends "#" and "@" which we'll use as "cursors" later.
s|.*|#@&;01000E211000/%00100Y310100U401100I%11100O500010f 10010J601010G711010H%00110B810110C901110F%00001 l10001-.01001X%11001Z:00101S%10101T%01101W?11101V'00011<<10011K(01011M)11011L=00111R-10111Q/01111N%11111P+10000A111110D0|

# Phase 1
:
  # Using "@" as a "cursor", substitute for each run of 5 binary digits the
  # two corresponding characters from the lookup table.
  s/@([01]{5})(.*;.*\1)(..)/\3@\2\3/
  t   # Loop (branch to `:`) as long as substitutions are made.

s/@;.*//       # Delete the "@" and lookup table

# Phase 2
s/#f /@/       # FS (f ) in letter mode (#); delete and switch to figure mode (@ cursor).
s/@ l/#/       # LS ( l) in figure mode (@); delete and switch to letter mode (# cursor).
s/#(.)./\1#/   # Letter mode; replace pair with first of pair; advance cursor.
s/@.(.)/\1@/   # Figure mode; replace pair with second of pair; advance cursor.
t              # If any substitutions were made, branch (loop) to `:`.

# Teardown
s/.<|[#@]//g   # Delete characters followed by < (ER) and cursor.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.