Перевести азбуку Морзе на основе длительности тона


36

Цель

Азбука Морзе часто представляется как звук. Учитывая поток битов, которые представляют, включен ли звук или нет, переведите поток в буквы, цифры и пробелы.

Международный азбука Морзе

конкретика

  • Поток битов анализируется на основе длины повторяющихся битов ВКЛ / ВЫКЛ.
    • 1 бит ON - это точка
    • 3 ON биты - это тире
    • 1 бит OFF ограничивает точки и тире
    • 3 ВЫКЛ биты символов
    • 7 ВЫКЛ битов отделяют слова (пробел)
  • Входные данные могут быть строкой или массивом. На вход допускаются только два уникальных символа / значения по вашему выбору. (например, 0/1, истина / ложь, запятая / пробел)
  • Вывод возвращает строку или выводится на стандартный вывод.

пример

Input:    101010100010001011101010001011101010001110111011100000001011101110001110111011100010111010001011101010001110101
Analysis: \--H--/   E   \---L---/   \---L---/   \----O----/\-- --/\---W---/   \----O----/   \--R--/   \---L---/   \--D--/
Output:   HELLO WORLD

Предположения

  • Поток всегда начинается и заканчивается битом ON.
  • Нет пробелов в начале или в конце.
  • Ввод всегда действителен.
  • Все буквы (без учета регистра) и цифры поддерживаются.

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

101010100010001011101010001011101010001110111011100000001011101110001110111011100010111010001011101010001110101
HELLO WORLD

10100000001011100011101110000000101110000000101011101000101000101010001010101
I AM A FISH

1010111011101110001110111011101110111000101110111011101110001110111010101
2017

101010001110111011100010101
SOS

счет

Это код гольф. Наименьший код подсчета байтов к этому времени на следующей неделе побеждает.


Может ли выход иметь пробел в конце?
Брайан Дж

Ответы:


9

APL (Дьялог) , 65 62 60 57 байтов

-3 благодаря нгн.

Функция молчаливого префикса.

CY'dfns'
morse'/|[-.]+'S'&'∘(⊃∘'/. -'¨6|'1+|(00)+'S 1)

Попробуйте онлайн! Заголовок, f←и Footer только , чтобы вызвать функцию от входа, сохраняя при этом количество байт Тио в. В обычном сеансе APL (в соответствии с полем ввода TIO) это не требуется .

⎕CY'dfns'с оп у в dfns рабочего пространства (библиотека)

() Применить эту молчаливую функцию:
'1+|(00)+'⎕S 1 PCRE S earch 1-серийный и четный-0-серийный и
6| остаток от деления длин совпадений при делении на 6
⊃∘'/. -'¨ для каждой длины совпадения, выбрать соответствующий символ из этой строки
'/|[-.]+'⎕S'&'∘ PCRE S косые черты и тире / точка -выбирает и возвращает эти
morse переводы из азбуки Морзе в обычный текст


5
Ого, никогда не знал, что у Дьялога есть встроенный азбука Морзе.
Захари

@ Zacharý Есть много, много встроенных в dfns.
Эрик Outgolfer

@ Zacharý Всегда проверяйте dfns !
Адам

Вы ссылаетесь на старую версию.
Эрик Outgolfer

Функция BF ...> _ <, вау.
Захари

8

Python 2 , 142 135 байт

lambda s:''.join(' E-T----Z-Q---RSWU--2FH-V980NIMA--1CBYX-6--GDOK534PLJ-7'[int('0'+l.replace('111','3'),16)%57]for l in s.split('000'))

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

Объяснение:

Разбивает строку на буквы 000( 0значит, пробел)

Заменяет каждый 111на 3и конвертирует в базу 16.

Затем каждое число модифицируется 57, что дает диапазон 0..54, который является индексом текущего символа.


Предыдущая версия, которая преобразована в базу 3:

Python 2 , 273 252 247 байт

lambda s:''.join(chr(dict(zip([0,242,161,134,125,122,121,202,229,238,241]+[2]*7+[5,67,70,22,1,43,25,40,4,53,23,49,8,7,26,52,77,16,13,2,14,41,17,68,71,76],[32]+range(48,91)))[int('0'+l.replace('111','2').replace('0',''),3)])for l in s.split('000'))

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

Предыдущая версия, которая преобразована в двоичный файл:

Python 2 , 282 261 256 байт

lambda s:''.join(chr(dict(zip([0,489335,96119,22391,5495,1367,341,1877,7637,30581,122333]+[2]*7+[23,469,1885,117,1,349,477,85,5,6007,471,373,119,29,1911,1501,7639,93,21,7,87,343,375,1879,7543,1909],[32]+range(48,91)))[int('0'+l,2)])for l in s.split('000'))

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


5

Рубин , 123 байта

->s{s.split(/0000?/).map{|r|r[0]?"YE9_0IZTO_BHKU58V_GR_SFA__1_4NP_60X_____C__D_ML7WQ3__2__J"[r.to_i(2)%253%132%74]:" "}*""}

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

Разбить входную строку по пределу символов. Используйте 3 или 4 бита OFF, чтобы пробелы были преобразованы в пустые строки. Возьмите базовые 2 значения каждого символа и приведите их в разумный диапазон (менее 60 возможных значений), используя модуль по 3 последовательным делениям.


Очень красиво сделано.
Восстановить Монику iamnotmaynard

2
Я уверен, что он работает для всех случаев, но если вы удалите его 0?из Regexp, он все равно будет работать для четырех тестовых случаев.
Иордания

4

Python , 175 168 байт

s=lambda t,f=''.join:f('; TEMNAIOGKDWRUS;;QZYCXBJP;L;FVH09;8;;;7;;;;;;;61;;;;;;;2;;;3;45'[int('1'+f('0'if j[1:]else j for j in i.split('0')),2)]for i in t.split('000'))

Сначала преобразуйте строку в список строк 0 (тире) / 1 (точка), добавьте префикс 1(для предотвращения начальных нулей и обработки пробелов), затем преобразуйте в двоичный файл.

Поскольку каждый код имеет длину не более 5, результат варьируется от 0 до 63 и может быть указан в строке.


1
Я независимо получил в основном то же решение, но 169 байтов:lambda s:''.join("_ TEMNAIOGKDWRUS__QZYCXBJP_L_FVH09_8___7_______61_______2___3_45"[int('1'+filter(int,l).replace('2','0'),2)]for l in s.replace('111','2').split('000'))
Алекс Варга

@AlexVarga Хорошее использование Python 2 filter!
Колера Су


3

Visual Basic .NET (.NET Core) , 252 байта

-7 байт благодаря @recursive

Function A(i)
For Each w In i.Split({"0000000"},0)
For Each l In w.Split({"000"},0)
Dim c=0
For Each p In l.Split("0")
c=c*2+1+p.Length\2
Next
A &="!ETIANMSURWDKGOHVF!L!PJBXCYZQ!!54!3!!!2!!!!!!!16!!!!!!!7!!!8!90"(c)
Next
A+=" "
Next
End Function

Функция, которая принимает строку 1s и 0s и возвращает строку. (На самом деле, жестким требованием является только 0for OFF. Все, что не OFFпредполагается ON).

Строковый литерал - это код Морзе, настроенный как двоичная куча в виде массива. VB.NET позволяет индексировать строки как массивы символов. \Это целое деление, с левой суб кучи для 1или правой суб кучи для111 .

Я использовал !как пробел, когда в этой куче нет значения. Нужно только правильно раскладывать индексы.

VB.NET позволяет вам вернуться, присвоив значение имени функции (в данном случае, A). Я просто итеративно выполняю конкатенацию строк ( &) для создания выходной строки. В самый первый раз, когда мне нужно использовать, &потому что использование +оставляет нулевой начальный символ, но в любое другое время я могу использовать +, который ведет себя так же, как &для строк.

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


1
Вы можете сохранить 7 байтов с помощью "!ETIANMSURWDKGOHVF!L!PJBXCYZQ!!5473!!8290!!!!!16", а затем индексировать с помощью M(c-c\48*22), а затем вы можете сохранить еще 4, даже не используя M, а просто используя строковый литерал, встроенный в строку.
рекурсивный

@ рекурсивный Я понимаю 4-х байтовый трюк, спасибо за помощь! У меня проблемы с пониманием того, как вы меняете индекс. Если я заменю строковый литерал, а затем использую M(c-c\48*22), я получаю индекс вне границ для случая 2017 года. Я думаю, что VB будет делать деление и умножение с одинаковым приоритетом; я пропускаю скобки?
Брайан Дж

Вы правы в отношении приоритета. c\48*22будет либо 0или 22. Это способ условно вычесть 22 из c, чтобы сделать Mкороче, «сложив» конец струны. Если это не сработает для вас, вы всегда можете удалить паренсы A &=(" ")еще на 2 байта. :)
рекурсив

И тогда вы можете изменить , &=чтобы +=и удалить еще два пробела.
рекурсивный

@ рекурсивный О, да! слишком много лишних паренов. Проблема с изменением на плюс заключается в том, что в начале строки у меня есть ведущий нулевой символ. Может быть, это не имеет большого значения, хотя.
Брайан Дж

3

JavaScript (ES6), 170 131 байт

s=>s.split`000`.map(e=>'  ETIANMSURWDKGOHVF L PJBXCYZQ'[c=+`0b${1+e.replace(/0?(111|1)/g,d=>+(d>1))}`]||'473168290 5'[c%11]).join``


Как это работает:

Если вы измените точки на 0, а тире на 1 и префикс с 1, вы получите двоичные числа, которые при преобразовании в десятичные числа дают вам:

  1. Буквы: 2 - 18, 20 и 22 - 29.
    Их можно преобразовать в правильные буквы, указав в ' ETIANMSURWDKGOHVF L PJBXCYZQ'.
  2. Числа: 32, 33, 35, 39, 47, 48, 56, 60, 62 и 63.
    Если мы возьмем эти числовые модули 11, мы получим числа 0 - 8 и 10, которые можно преобразовать в правильные числа с помощью индексация в '473168290 5'.

Программа разделяется на символы, а затем преобразует каждый символ в точки и тире, которые преобразуются в соответствующие выходные данные на основе вышеуказанных правил.


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


3

Python 2 , 127 байт

lambda s:''.join("IVMB  T  K 9LZF 1HWO3 GUS4 8 7A  E QR 26   NJX    Y0P 5D  C"[(int('0'+l)^2162146)%59]for l in s.split('000'))

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

Построение решения TFeld путем удаления замены и работы с базой 10 ценой побитового xor и более длинной ссылочной строки.


2

PHP, 321 284 байта

Сохранено 37 байтов благодаря @ovs

$a=array_flip([242,161,134,125,122,121,202,229,238,241,5,67,70,22,1,43,25,40,4,53,23,49,8,7,26,52,77,16,13,2,14,41,17,68,71,76]);foreach(split('0000000',$argv[1])as$w){foreach(split('000',$w)as$m){echo($v=$a[base_convert(str_replace([111,0],[2,],$m),3,10)])>9?chr($v+55):$v;}echo' ';}  

Предыдущая версия (321 байт)

$a=array_flip([22222,12222,11222,11122,11112,11111,21111,22111,22211,22221,12,2111,2121,211,1,1121,221,1111,11,1222,212,1211,22,21,222,1221,2212,121,111,2,112,1112,122,2112,2122,2211]);foreach(split('0000000',$argv[1])as$w){foreach(split('000',$w)as$m){echo($v=$a[str_replace([111,0],[2,],$m)])>9?chr($v+55):$v;}echo' ';}

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

Безголовая версия:

$a=array_flip(
// Building an array $a with every Morse letter representation (1=dot, 2=dash) and flip it
               [22222,12222,11222,11122,11112,
                // 01234
                11111,21111,22111,22211,22221,
                // 56789
                12,2111,2121,211,1,1121,221,
                // ABCDEFG
                1111,11,1222,212,1211,22,
                // HIJKLM
                21,222,1221,2212,121,111,2,
                // NOPQRST
                112,1112,122,2112,2122,2211]);
                // UVWXYZ
foreach (split('0000000', $argv[1]) as $w){
// for each word (separate with 7 consecutive zeroes)
    foreach (split('000',$w) as $m){
    // for each letter (separate with 3 consecutive zeroes)
        echo ($v = $a[str_replace([111,0],[2,],$m)]) > 9
        // Replace '111' with '2' and '0' with nothing and find $v, the corresponding entry in the array $a
            ? chr($v+55)
            // If > 9th element, then letter => echo the ASCII code equal to $v+55
            : $v;
            // Else echo $v
    }
    echo ' ';
    // Echo a space
}

2

Java (OpenJDK 8) , 370 байт

s->{String r="";for(String t:s.split("0000000")){for(String u:t.split("000"))for(int x[]={1,7,5,21,29,23,87,93,119,85,117,341,375,343,373,471,477,349,469,1877,1367,1909,1879,1501,1911,1885,7637,5495,7543,7639,6007,30581,22391,122333,96119,489335},i=x.length;i-->0;)if(u.equals(Long.toString(x[i],2)))r+="ETISNAURMHD5WVLKGFB64ZXPOC73YQJ82910".charAt(i);r+=" ";}return r;}

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

  • 3 байта сохранены благодаря @Jeutnarg.

1
можно сбрить немного, используя Long.toString (x [i], 2) вместо Integer.toString (x [i], 2)
Jeutnarg

2

GNU sed , 261 + 1 = 262 байта

+1 байт за -rфлаг.

s/000/;/g
s/111/_/g
s/0//g
s/$/;:51111141111_3111__211___i1____6_11117__1118___119____10_____H1111V111_F11_1L1_11P1__1J1___B_111X_11_C_1_1Y_1__Z__11Q__1_S111U11_R1_1W1__D_11K_1_N__1G__1O___I11A1_M__E1T_/
:
s/([1_]+);(.*([^1_])\1)/\3\2/
t
y/i/1/
s/;/ /g
s/:.*//g

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

объяснение

Это очень простое решение для таблицы поиска.

Первые три строки преобразуют входные данные, чтобы штрихи были _s, а точки - 1s. Во-первых, 000s заменяются на ;, поэтому символы отделяются ;и слова на ;;0. Затем 111s заменяются на, _а все остальные 0s отбрасываются, оставляя 1s для точек.

s/000/;/g
s/111/_/g
s/0//g

Следующая строка добавляет таблицу поиска. Он принимает форму, cmcmcm...где cнаходится символ и mпредставляет собой последовательность _s и 1s, представляющих его.iзаменяется 1в таблице для устранения неоднозначности. Поскольку регулярные выражения в sed всегда жадные, таблица сортируется от самого длинного до самого короткого кода (например, 1_совпадения A1_вместо i1____).

s/$/;:51111141111_3111__211___i1____6_11117__1118___119____10_____H1111V111_F11_1L1_11P1__1J1___B_111X_11_C_1_1Y_1__Z__11Q__1_S111U11_R1_1W1__D_11K_1_N__1G__1O___I11A1_M__E1T_/

Далее в цикле каждая последовательность _ s и 1s (и последующие ;) заменяется соответствующим символом:

:
s/([1_]+);(.*([^1_])\1)/\3\2/
t

Наконец, cleanup: is заменяются на 1s, остальные ;s - это пробелы, а таблица поиска удаляется:

y/i/1/
s/;/ /g
s/:.*//g


1

JavaScript (ES6), 104 102 101 99 байт

s=>s.split`000`.map(n=>" _T__9VEFO0K7MX_CGS__LU1RYIJ845__Z_B_D6QP_3__AHNW2"[n*1741%8360%51]).join``

Контрольные примеры

Как?

Поскольку преобразование из двоичных в десятичные байты стоит, мы используем хеш-функцию, которая работает непосредственно с двоичными блоками, интерпретируемыми в базе 10.

пример

dot dash dot dot = 101110101
101110101 * 1741 = 176032685841
176032685841 % 8360 = 3081
3081 % 51 = 21

--> The 21st character in the lookup table is 'L' (0-indexed).

Мне очень нравится этот одностадийный подход. Насколько велик поиск, который вы выполнили, чтобы уместить эти 37 выходов в идеальный хэш размером 50 с достаточно короткой функцией?
Джайприч

@jayprich Это было грубо. Это было почти год назад, поэтому я не помню точно, как. :) Скорее всего, я перепробовал все n*p%m0%m1для1п<10000, 1<м0<10000 а также 1<м1<100,
Арно

1

Retina , 144 138 130 103 байт

T`d`@#
^|@@@

 @?#
E
{T`L#@`R6_BI_Z5S1C_GD8__\L\HNF3P__7_`\w@#
T`589B-INPRSZ#@`490XYKT2\OVAMJWUQ_`\w##

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Объяснение:

T`d`@#

Измените двоичные цифры на другие символы, потому что 0 и 1 являются допустимыми выходами.

^|@@@
 

Вставьте пробел перед каждым символом и два пробела между словами.

 @?#
E

Предположим, что все символы являются Es.

{T`L#@`R6_BI_Z5S1C_GD8__\L\HNF3P__7_`\w@#

Переведите все буквы, предполагая, что за ними будет следовать точка. Например, если у нас есть E, и мы видим вторую точку (мы использовали первую, когда мы вставили E), то она переводится в I. Для букв, за которыми юридически может следовать только тире, они переводятся с этим Предположение, а затем тире потребляется на следующем этапе. Остальные буквы удаляются (сохраняя Lстоимость в байте).

T`589B-INPRSZ#@`490XYKT2\OVAMJWUQ_`\w##

Если выяснится, что на самом деле за ними последовала тире, исправьте неправильные переводы. Это также потребляет тире, когда это предполагалось на предыдущем этапе. Оба перевода повторяются до тех пор, пока не будут использованы все точки и тире.


0

Perl 5 , 241 + 1 ( -p) = 242 байта

%k=map{(23,469,1885,117,1,349,477,85,5,6007,471,373,119,29,1911,1501,7639,93,21,7,87,343,375,1879,7543,1909,489335,96119,22391,5495,1367,341,1877,7637,30581,122333)[$i++]=>$_}A..Z,0..9;map{$\.=$k{oct"0b$_"}for split/000/;$\.=$"}split/0{7}/}{

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


0

PHP, 181 + 1 байт

foreach(explode(_,strtr($argn. 0,[1110=>1,10=>0,"0000"=>_A,"00"=>_]))as$t)echo$t<A?~$t[-5]?(10+substr_count($t,0)*(1-2*$t[-5]))%10:__ETIANMSURWDKGOHVF_L_PJBXCYZQ[bindec("1$t")]:" ";

Запустите как трубу с -nRили попробуйте онлайн .


0

ES6 , 268 байт

Использует ASCII-кодирование после сопоставления от представления 36 азбуки Морзе до позиции индекса. Не мой лучший день в гольф, но это заняло всего около 15 минут.

s=>s.split('00000').map(w=>String.fromCharCode.apply({},w.split('000').map(c=>"ahkn,225z,h9z,48n,11z,9h,1g5,5w5,nlh,2me5,,,,,,,,n,d1,1gd,39,1,9p,d9,2d,5,4mv,d3,ad,3b,t,1h3,15p,5w7,2l,l,7,2f,9j,af,1g7,1h1".split(',').indexOf(parseInt(c,2).toString(36))+48))).join(' ')

Легче читать (вроде):

s=>
s
.split('00000')
.map(w=>
	String.fromCharCode.apply({},
		w.split('000')
			.map(c=>
				"ahkn,225z,h9z,48n,11z,9h,1g5,5w5,nlh,2me5,,,,,,,,n,d1,1gd,39,1,9p,d9,2d,5,4mv,d3,ad,3b,t,1h3,15p,5w7,2l,l,7,2f,9j,af,1g7,1h1"
				.split(',')
				.indexOf(
					parseInt(c,2).toString(36)
				)+48)
			)
	).join(' ')


0

Wolfram Language (Mathematica) , 288 байтов

Мысль о чтении данных в двоичном виде из файла, но это трудно объяснить. База 36 казалась хорошим компромиссным способом эффективного хранения данных.

Принимает строку из 0 и 1 в качестве входных данных. Выполняет серию замен, начиная с серий 7 нулей, затем серий 3, затем самых длинных двоичных букв вплоть до самых коротких. Порядок замены важен.

StringReplace[#,Thread@Rule[Join[{"0000000","000"},#~FromDigits~36~IntegerString~2&/@StringSplit@"ahkn 2me5 225z nlh h9z 5w7 5w5 5tj 4mv 48n 1h3 1h1 1gd 1g7 1g5 15p 11z d9 d3 d1 af ad 9p 9j 9h 3b 39 2l 2f 2d t n l 7 5 1"],Insert[Characters@" 09182Q7YJ3OZCX6P4GKBWLFV5MDRUHNASTIE","",2]]]&

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


Подождите, Mathematica не имеет встроенного кода Морзе?
Захари

Еще нет! Я проверил.
Келли Лоудер

0

Perl 5 , 195 байт

Код 194 байта + 1 для -p.

%h=map{$_,(A..Z,0..9)[$i++]}unpack"S26I2S7I","\xd5]u]\xddUw\xd7uww\xdd\xd7]WWwWwuwwwwwWwWUU\xd5uw\xdd\xdd";s/0{7}/ /g;s/(\d+?)(000|\b)/$h{oct"0b$1"}/ge

Я не мог заставить это работать только со стандартной упакованной двоичной строкой, я должен был избегать старших байтов, иначе я был бы на 171, если кто-нибудь знает, что я пропустил, или почему это ломается, это было бы здорово !

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

объяснение

Двоичная строка представляет собой packредактор список номеров , которые имеют отношение к персонажам Морзе ( 101011101- 349дляF т.д.) , и это заархивировано с диапазонами A..Z,0..9и использовать в качестве поиска. В s///выражении заменить все пробеги семи 0секунд с пространством , а затем все пробеги цифр, разделенные тремя 0с или границами слова \b, с их соответствующей клавишей из %hхэша.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.