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

Задача

Самый короткий код по количеству символов, который будет вводить строку, используя только алфавитные символы (верхний и нижний регистр), цифры, запятые, периоды и знак вопроса и возвращает представление строки в коде Морзе. Выход кодов Морзе должен состоять из тире (-, ASCII 0x2D) для длинного звукового сигнала (AKA 'dah') и точки (., ASCII 0x2E) для короткого звукового сигнала (AKA 'dit').

Каждая буква должна быть разделена пробелом (' ', ASCII 0x20), и каждое слово должно быть разделено косой чертой (/, ASCII 0x2F).

Таблица кодов Морзе:

alt text http://liranuna.com/junk/morse.gif

Тестовые примеры:

Input:
    Hello world

Output:
    .... . .-.. .-.. --- / .-- --- .-. .-.. -..

Input:
    Hello, Stackoverflow.

Output:
    .... . .-.. .-.. --- --..-- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- .-.-.-

Количество кодов включает ввод/вывод (то есть полную программу).

Ответ 1

C (131 символ)

Да, 13 1!

main(c){for(;c=c?c:(c=toupper(getch())-32)?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putch(c/2?46-c%2:0);}

Я выделил еще несколько символов, объединив логику из циклов while и for в один цикл for и перемещая объявление переменной c в определение main как входной параметр. Этот последний метод, который я заимствовал из ответил на другой вызов.


Для тех, кто пытается проверить программу с помощью GCC или с редакторами ASCII, вам может понадобиться следующая, немного более длинная версия:

main(c){for(;c=c?c:(c=toupper(getchar())-32)?c<0?1:
"\x95#\x8CKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putchar(c/2?46-c%2:32);}

Эта версия на 17 символов длиннее (весит около 148), из-за следующих изменений:

  • +4: getchar() и putchar() вместо непортативных getch() и putch()
  • +6: escape-коды для двух символов вместо символов, отличных от ASCII
  • +1: 32 вместо 0 для символа пробела
  • +6: добавлено "c<0?1:" для подавления мусора с символов, меньших, чем ASCII 32 (а именно, от '\n'). Вы все равно получите мусор из любого из !"#$%&'()*+[\]^_ `{|}~ или что-нибудь выше ASCII 126.

Это должно сделать код полностью переносимым. Скомпилировать с помощью:

gcc -std=c89 -funsigned-char morse.c

-std=c89 не является обязательным. Тем не менее, требуется -funsigned-char, или вы получите мусор для запятой и полной остановки.


135 символов

c;main(){while(c=toupper(getch()))for(c=c-32?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-44]-34:-3;c;c/=2)putch(c/2?46-c%2:0);}

По-моему, эта последняя версия гораздо более визуально привлекательна. И нет, он не переносимый, и он больше не защищен от ввода вне пределов. Он также имеет довольно плохой интерфейс, принимая посимвольный ввод и преобразовывая его в код Морзе и не имея условия выхода (вам нужно нажать Ctrl + Break). Но портативный, надежный код с приятным интерфейсом не требовал.

Ниже приведено краткое описание кода:

main(c){
    while(c = toupper(getch())) /* well, *sort of* an exit condition */
        for(c =
            c - 32 ? // effectively: "if not space character"
            "•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"[c - 44] - 34
            /* This array contains a binary representation of the Morse Code
             * for all characters between comma (ASCII 44) and capital Z.
             * The values are offset by 34 to make them all representable
             * without escape codes (as long as chars > 127 are allowed).
             * See explanation after code for encoding format.
             */
            : -3; /* if input char is space, c = -3
                   * this is chosen because -3 % 2 = -1 (and 46 - -1 = 47)
                   * and -3 / 2 / 2 = 0 (with integer truncation)
                   */
            c; /* continue loop while c != 0 */
            c /= 2) /* shift down to the next bit */
                putch(c / 2 ? /* this will be 0 if we're down to our guard bit */
                    46 - c % 2 /* We'll end up with 45 (-), 46 (.), or 47 (/).
                                * It very convenient that the three characters
                                * we need for this exercise are all consecutive.
                                */
                    : 0 /* we're at the guard bit, output blank space */
                );
}

Каждый символ в длинной строке кода содержит закодированный код Морзе для одного текстового символа. Каждый бит кодированного символа представляет либо тире, либо точку. Один представляет тире, а нуль представляет точку. Меньшезначный бит представляет собой первый штрих или точку в коде Морзе. Окончательный бит "охранник" определяет длину кода. То есть, самый старший бит в каждом закодированном символе представляет конец кода и не печатается. Без этого защитного бита символы с конечными точками не могут быть напечатаны правильно.

Например, буква "L" является ".-.." в коде Морзе. Чтобы представить это в двоичном формате, нам нужны 0, 1 и еще два 0, начиная с младшего значащего бита: 0010. Отбросьте еще 1 на бит защиты, и у нас есть наш закодированный код Морзе: 10010 или десятичный 18. Добавьте смещение +34, чтобы получить 52, что является значением ASCII символа "4". Таким образом, кодированный массив символов имеет "4" в качестве 33-го символа (индекс 32).

Этот метод похож на тот, который используется для кодирования символов в ACoolie, strager's (2)Miles's, pingw33n's, Alec и , но немного проще, требуя только одной операции на бит (смещение/деление), а не два (смещение/деление и декрементирование).

EDIT:
Просматривая остальную часть реализаций, я вижу, что Alec и Anon придумали эту схему кодирования - используя сторожевой бит - прежде чем я это сделал. Решение Anon особенно интересно, используя функцию Python bin и отделяя префикс "0b" и бит защиты с [3:], а не зацикливание, изменение и перемещение, как это делали Алек и я.

В качестве бонуса эта версия также обрабатывает дефис (-....-), слэш (-..-.), двоеточие (---...), точка с запятой (-.-.-.), равно (-...-), а при знаке ( .--.-.). До тех пор, пока разрешены 8-битные символы, эти символы не требуют дополнительных байтов кода для поддержки. Никакой символ не может поддерживаться с этой версией без добавления длины к коду (если только коды Морзе больше/меньше знаков).

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


Хорошо, предположительно, пользовательский интерфейс может сосать, правильно? Итак, заимствование из strager, Я заменил gets(), который обеспечивает буферизованный вход эхо-сигнала, с getch(), который обеспечивает небуферизованный, неэкранированный ввод символов. Это означает, что каждый персонаж, который вы вводите, сразу переводится в код Морзе на экране. Может быть, это круто. Он больше не работает ни с аргументом stdin, ни с командной строкой, но это довольно чертовски мало.

Я сохранил старый код ниже, однако, для справки. Здесь новый.

Новый код с проверкой границ, 171 символ:

W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?c>77|c<31?0:W("œ*~*hXPLJIYaeg*****u*.AC5+;[email protected]=0/8?F31,2:4BDE"
[c-31]-42):putch(47),putch(0);}

Enter прерывает цикл и выходит из программы.

Новый код без проверки границ, 159 символов:

W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?W("œ*~*hXPLJIYaeg*****u*.AC5+;[email protected]=0/8?F31,2:4BDE"[c-31]-42):
putch(47),putch(0);}

Ниже следует старый код 196/177 с некоторым объяснением:

W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,c,s[99];gets(s);
for(p=s;*p;)c=*p++,c=toupper(c),c=c-32?c>90|c<44?0:W(
"œ*~*hXPLJIYaeg*****u*.AC5+;[email protected]=0/8?F31,2:4BDE"[c-44]-42):
putch(47),putch(0);}

Это основано на ответе Andrea Python, используя тот же метод для генерации кода Морзе, как и в этом ответе. Но вместо того, чтобы хранить кодирующие символы один за другим и находить их индексы, я хранил индексы один за другим и просматривал их по символу (аналогично моему более раннему ответу). Это предотвращает длительные промежутки в конце, которые вызвали проблемы для более ранних разработчиков.

Как до, я использовал символ, который больше 127. Преобразование его в ASCII-only добавляет 3 символа. Первый символ длинной строки должен быть заменен на \x9C. Смещение необходимо на этот раз, иначе большое количество символов будет меньше 32 и должно быть представлено escape-кодами.

Также как и раньше, обработка аргумента командной строки вместо stdin добавляет 2 символа, а использование символа реального пробела между кодами добавляет 1 символ.

С другой стороны, некоторые из других подпрограмм здесь не занимаются вводом вне допустимого диапазона [,.0-9\A-Za-z]. Если такая обработка была удалена из этой процедуры, тогда 19 символов могут быть удалены, в результате чего суммарная сумма будет равна 177 символам. Но если это будет сделано, и недействительный ввод будет передан в эту программу, он может сработать и сжечь.

Код в этом случае может быть:

W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,s[99];gets(s);
for(p=s;*p;p++)*p=*p-32?W(
"œ*~*hXPLJIYaeg*****u*.AC5+;[email protected]=0/8?F31,2:4BDE"
[toupper(*p)-44]-42):putch(47),putch(0);}

Ответ 3

Perl, 170 символов (с небольшой помощью от опытного игрока в гольф mauke). Обернутый для ясности; все символы новой строки являются съемными.

$_=uc<>;y,. ,|/,;s/./$& /g;@m{A..Z,0..9,qw(| , ?)}=
".-NINNN..]IN-NII..AMN-AI---.M-ANMAA.I.-].AIAA-NANMMIOMAOUMSMSAH.B.MSOIONARZMIZ"
=~/../g;1while s![]\w|,?]!$m{$&}!;print

Объяснение:

  • Извлеките словарь морзе. Каждый символ определяется в виде двух символов, которые могут быть либо буквальными точками, либо тире, либо ссылкой на значение другого определенного char. E и T содержат фиктивные символы, чтобы избежать дешифрования декодера; мы удалим их позже.
  • Прочитайте и отформатируйте ввод. "Hello world" становится "H E L L O / W O R L D"
  • Следующий шаг зависит от того, что входные и выходные словари различаются, поэтому поверните точки на входе в неиспользованный char (вертикальная панель, |)
  • Замените любой char на вход, который встречается в словаре morse с его значением в словаре, до тех пор, пока не произойдет замена.
  • Удалите фиктивный char, указанный на шаге 1.
  • Распечатайте вывод.

В окончательной версии словарь оптимизирован для эффективности выполнения:

  • Все символы с одним символом (E и T) и двухсимвольные символы (A, I, M и N) определяются непосредственно и декодируются за один проход.
  • Все символы с тремя символами определяются в терминах символа с двумя символами и буквального символа, декодирования в два прохода.
  • Все символы с четырьмя символами определяются в двух символах с двумя символами, декодирование в два прохода с тремя заменами.
  • Пяти- и шестисимвольные символы (цифры и пунктуация) декодируются в три прохода с четырьмя или пятью заменами соответственно.

Так как код для гольфа только заменяет один символ на цикл (для сохранения одного символа кода!) количество циклов ограничено в пять раз больше длины ввода (в три раза больше длины ввода, если используются только алфавиты), Но добавив операцию g в s///, количество циклов ограничено тремя (два, если используются только алфавиты).

Пример преобразования:

Hello 123
H E L L O / 1 2 3
II .] AI AI M- / AO UM SM
.... . .-.. .-.. --- / .-M- .A-- I.--
.... . .-.. .-.. --- / .---- ..--- ...--

Ответ 4

Понимание списка Python, 159-символьный однострочный

for c in raw_input().upper():print c<","and"/"or bin(ord("•ƒwTaQIECBRZ^`šŒ#S#n|':<.$402&9/6)(18?,*%+3-;=>"[ord(c)-44])-34)[3:].translate(" "*47+"/.-"+" "*206),

Использует подобную упаковку данных P Daddy C, но не сохраняет биты в обратном порядке и использует bin() для извлечения данных, а не для арифметики. Отметим также, что пробелы обнаруживаются с использованием неравенства; он считает, что каждый символ "меньше, чем запятая" является пространством.

цикл Python for, 205 символов, включая символы новой строки

for a in raw_input().upper():
 q='_ETIANMSURWDKGOHVF_L_PJBXCYZQ__54_3___2__+____16=/_____7___8_90'.find(a);s=''
 while q>0:s='-.'[q%2]+s;q=~-q/2
 print['/','--..--','..--..','.-.-.-',''][' ,?.'.find(a)]+s,

Ответ 5

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

Рассмотрим строку:

 --..--..-.-.-..--...----.....-----.--/

который содержит все необходимые последовательности в качестве подстрок. Мы могли бы кодировать символы смещением и длиной следующим образом:

       ET  RRRIIGGGJJJJ    
--..--..-.-.-..--...----.....-----.--/
          CCCC  DD WWW       00000
,,,,,,   AALLLL BBBB        11111
--..--..-.-.-..--...----.....-----.--/
  ??????  KKK  MMSSS       22222   
        FFFF  PPPP        33333
--..--..-.-.-..--...----.....-----.--/
        UUU XXXX         44444       
          NN  PPPP  OOO 55555
--..--..-.-.-..--...----.....-----.--/
               ZZZZ    66666
                      77777      YYYY
--..--..-.-.-..--...----.....-----.--/
       ......        88888 HHHH
                    99999 VVVV  QQQQ
--..--..-.-.-..--...----.....-----.--/

с пространством (т.е. границей слова), начинающимся и заканчивающимся на конечном символе ( "/" ). Не стесняйтесь использовать его, если вы видите хороший способ.

Большинство коротких символов имеют, конечно, несколько возможных кодировок.


P Daddy нашел более короткую версию этого трюка (и теперь я вижу, по крайней мере, некоторую избыточность здесь) и сделал хорошую реализацию c. Alec выполнил реализацию python с первой (ошибкой и неполностью) версией. Хоббс сделал довольно компактную версию perl, которую я вообще не понимаю.

Ответ 6

J, 124 130 134 символы

'.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`[email protected]*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper

J бьет C! Отлично!

Использование:

   '.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`[email protected]B4*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper 'Hello World'
.... . .-.. .-.. --- / .-- --- .-. .-.. -.. 

   '.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`[email protected]*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper 'Hello, Stackoverflow.'
.... . .-.. .-.. --- .-.-.- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- --..-- 

Ответ 7

Python 3 Один вкладыш: 172 символа

print(' '.join('/'if c==' 'else''.join('.'if x=='0'else'-'for x in bin(ord("ijÁĕÁÿïçãáàðøüþÁÁÁÁÁČÁÅ×ÚÌÂÒÎÐÄ×ÍÔÇÆÏÖÝÊÈÃÉÑËÙÛÜ"[ord(c)-44])-192)[3:])for c in input().upper()))

(Кодирование таблицы транслирования в кодовых точках Юникода. Хорошо работает, и они отлично отображаются в моем тесте на моей машине с Windows Vista.)

Отредактировано до 184 символов, удалив ненужные пробелы и скобки (создание списка comps gen exps).

Изменить снова: больше удаленных пробелов, которые я даже не знал, было возможно, прежде чем видеть другие ответы здесь - так до 176.

Изменить снова до 172 (woo woo!), используя ".join вместо" ".join и делать пробелы отдельно. (Дух!)

Ответ 8

С# 266 символов

Решение 131 char C, переведенное на С#, дает 266 символов:

foreach(var i in Encoding.ASCII.GetBytes(args[0].ToUpper())){var c=(int)i;for(c=(c-32!=0)?Encoding.ASCII.GetBytes("•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5")[c-44]-34:-3;c!=0;c/=2)Console.Write(Encoding.ASCII.GetChars(new byte[]{(byte)((c/2!=0)?46-c%2:0)}));}

который более читаем как:

foreach (var i in Encoding.ASCII.GetBytes(args[0].ToUpper()))
{
    var c = (int)i;
    for (c = ((c - 32) != 0) ? Encoding.ASCII.GetBytes("•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5")[c - 44] - 34 : -3
        ; c != 0
        ; c /= 2)
        Console.Write(Encoding.ASCII.GetChars(new byte[] { (byte)((c / 2 != 0) ? 46 - c % 2 : 0) }));
}

Ответ 9

Golfscript - 106 символов - NO FUNNY CHARS:)

newline в конце ввода не поддерживается, поэтому используйте что-то вроде этого

echo -n Hello, Stackoverflow| ../golfscript.rb morse.gs

' '/{{.32|"!etianmsurwdkgohvf!l!pjbxcyzq"?)"UsL?/'#! 08<>"@".,?0123456789"?=or
2base(;>{'.-'\=}%' '}%}%'/'*

Буквы являются особым случаем и преобразуются в строчные буквы и упорядочены в их двоичных положениях.
Все остальное выполняется таблицей переводов

Ответ 10

Python

Неполное решение, но, возможно, кто-то может сделать из него полное решение. Не обрабатывает цифры или знаки препинания, но весит всего 154 символа.

def e(l):
 i='_etianmsurwdkgohvf_l_pjbxcyzq'.find(l.lower());v=''
 while i>0:v='-.'[i%2]+v;i=(i-1)/2;return v or '/'
def enc(s):return ' '.join(map(e,s))

Ответ 11

Здесь мой вклад в качестве консольного приложения в VB.Net

Module MorseCodeConverter

    Dim M() As String = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."}

    Sub Main()
        Dim I, O
        Dim a, b

        While True
            I = Console.ReadLine()
            O = ""

            For Each a In I
                b = AscW(UCase(a))
                If b > 64 And b < 91 Then
                    O &= M(b - 65) & " "
                ElseIf b > 47 And b < 58 Then
                    O &= M(b - 22) & " "
                ElseIf b = 46 Then
                    O &= ".-.-.- "
                ElseIf b = 44 Then
                    O &= "--..-- "
                ElseIf b = 63 Then
                    O &= "..--.. "
                Else
                    O &= "/"
                End If

            Next

            Console.WriteLine(O)
        End While


    End Sub

End Module

Я оставил ему пустое пространство, чтобы сделать его доступным для чтения. Всего 1100 символов. Он будет считывать ввод из командной строки, по одной строке за раз и отправлять соответствующий вывод обратно в выходной поток. Сжатая версия ниже, всего 632 символа.

Module Q
    Dim M() As String={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."}
    Sub Main()
        Dim I,O,a,b:While 1:I=Console.ReadLine():O="":For Each a In I:b=AscW(UCase(a)):If b>64 And b<91 Then:O &=M(b-65)&" ":ElseIf b>47 And b<58 Then:O &=M(b-22)&" ":ElseIf b=46 Then:O &=".-.-.- ":ElseIf b=44 Then:O &="--..-- ":ElseIf b=63 Then:O &= "..--.. ":Else:O &="/":End IF:Next:Console.WriteLine(O):End While
    End Sub
End Module

Ответ 12

C (248 символов)

Другое дерево-решение.

#define O putchar
char z[99],*t=
" ETINAMSDRGUKWOHBL~FCPJVX~YZQ~~54~3~~~2~~+~~~~16=/~~.~~7,~~8~90";c,p,i=0;
main(){gets(z);while(c=z[i++]){c-46?c-44?c:O(45):O(c);c=c>96?c-32:c;p=-1;
while(t[++p]!=c);for(;p;p/=2){O(45+p--%2);}c-32?O(32):(O(47),O(c));}}

Может быть ошибки в исходном дереве, потому что wikipedia кажется неправильным или, может быть, я что-то не понял.

Ответ 13

F #, 256 символов

let rec D i=if i=16 then" "else
 let x=int"U*:+F8c]uWjGbJ0-0Dnmd0BiC5?\4o`h7f>9[1E=pr_".[i]-32
 if x>43 then"-"+D(x-43)else"."+D x
let M(s:string)=s.ToUpper()|>Seq.fold(fun s c->s+match c with
|' '->"/ "|','->"--..-- "|'.'->".-.-.- "|_->D(int c-48))""

Например

M("Hello, Stack.") |> printfn "%s"

дает

.... . .-.. .-.. --- --..-- / ... - .- -.-. -.- .-.-.-

Я думаю, что моя техника может быть уникальной до сих пор. Идея такова:

  • существует диапазон символов ascii, который покрывает большую часть того, что мы хотим (0..Z)
  • в этом диапазоне всего 43 символа
  • таким образом мы можем кодировать один бит (тире или точку) плюс "следующий символ" в диапазоне 86 символов
  • диапазон ascii (32-117) является "пригодным для печати" и может служить в качестве диапазона 86- char
  • поэтому строковый литерал кодирует таблицу вдоль этих строк

Там немного больше, но это суть. Запятая, период и пространство не находятся в диапазоне 0..Z, поэтому они обрабатываются специально "совпадением". Некоторые "неиспользуемые" символы в диапазоне 0..Z(например, ';') используются в таблице в качестве суффиксов других переводов морзе, которые сами по себе не являются "буквами".

Ответ 14

C (233 символа)

W(n,p){while(n--)putch(".-.-.--.--..--..-.....-----..../"[p++]);}main(){
char*p,c,s[99];gets(s);for(p=s;*p;){c=*p++;c=toupper(c);c=c>90?35:c-32?
"È#À#¶µ´³²±°¹¸·#####Ê#@i Že‘J•aEAv„…`q!j"d‰ƒˆ"[c-44]:63;c-35?
W(c>>5,c&31):0;putch(0);}}

Это вводит данные из stdin. Ввод ввода из командной строки добавляет 2 символа. Вместо:

...main(){char*p,c,s[99];gets(s);for(p=s;...

вы получаете:

...main(int i,char**s){char*p,c;for(p=s[1];...

Я использую кодовую страницу Windows-1252 для символов выше 127, и я не уверен, как они появятся в других браузерах. Я заметил, что в моем браузере хотя бы (Google Chrome) два символа (между "@" и "i" ) не отображаются. Если вы копируете из браузера и вставляете в текстовый редактор, тем не менее, они появляются, хотя и в виде маленьких ящиков.

Он может быть преобразован в ASCII-only, но это добавляет 24 символа, увеличивая число символов до 257. Для этого я сначала смещаю каждый символ в строке на -64, сводя к минимуму количество символов, которые больше, чем 127. Затем я заменяю символы \x XX символов, когда это необходимо. Он меняет это:

...c>90?35:c-32?"È#À#¶µ´³²±°¹¸·#####Ê#@i Že‘J•aEAv„…`q!j"d‰ƒˆ"[c-44]:63;
c-35?W(...

:

...c>90?99:c-32?"\x88#\x80#vutsrqpyxw#####\x8A#\0PA)\xE0N%Q\nU!O\5\1\66DE 1
\xE1*S$ICH"[c-44]+64:63;c-99?W(...

Здесь более красиво отформатированная и прокомментированная версия кода:

/* writes `n` characters from internal string to stdout, starting with
 * index `p` */
W(n,p){
    while(n--)
        /* warning for using putch without declaring it */
        putch(".-.-.--.--..--..-.....-----..../"[p++]);

        /* dmckee noticed (http://tinyurl.com/n4eart) the overlap of the
         * various morse codes and created a 37-character-length string that
         * contained the morse code for every required character (except for
         * space).  You just have to know the start index and length of each
         * one.  With the same idea, I came up with this 32-character-length
         * string.  This not only saves 5 characters here, but means that I
         * can encode the start indexes with only 5 bits below.
         *
         * The start and length of each character are as follows:
         *
         *   A:  0,2    K:  1,3    U: 10,3    4: 18,5
         *   B: 16,4    L: 15,4    V: 19,4    5: 17,5
         *   C:  1,4    M:  5,2    W:  4,3    6: 16,5
         *   D:  9,3    N:  1,2    X:  9,4    7: 25,5
         *   E:  0,1    O: 22,3    Y:  3,4    8: 24,5
         *   F: 14,4    P:  4,4    Z:  8,4    9: 23,5
         *   G:  5,3    Q:  5,4    0: 22,5    .:  0,6
         *   H: 17,4    R:  0,3    1: 21,5    ,:  8,6
         *   I: 20,2    S: 17,3    2: 20,5    ?: 10,6
         *   J: 21,4    T:  1,1    3: 19,5
         */
}

main(){ /* yuck, but it compiles and runs */
    char *p, c, s[99];
    /* p is a pointer within the input string */
    /* c saves from having to do `*p` all the time */
    /* s is the buffer for the input string */

    gets(s); /* warning for use without declaring */

    for(p=s; *p;){ /* begin with start of input, go till null character */
        c = *p++; /* grab *p into c, increment p.
                   * incrementing p here instead of in the for loop saves
                   * one character */

        c=toupper(c); /* warning for use without declaring */

        c = c > 90 ? 35 : c - 32 ?
            "È#À#¶µ´³²±°¹¸·#####Ê#@i Že‘J•aEAv„…`q!j"d‰ƒˆ"[c - 44] : 63;

        /**** OR, for the ASCII version ****/

        c = c > 90 ? 99 : c - 32 ?
           "\x88#\x80#vutsrqpyxw#####\x8A#\0PA)\xE0N%Q\nU!O\5\1\66DE 1\xE1"
           "*S$ICH"[c - 44] + 64 : 63;

        /* Here where it gets hairy.
         *
         * What I've done is encode the (start,length) values listed in the
         * comment in the W function into one byte per character.  The start
         * index is encoded in the low 5 bits, and the length is encoded in
         * the high 3 bits, so encoded_char = (char)(length << 5 | position).
         * For the longer, ASCII-only version, 64 is subtracted from the
         * encoded byte to reduce the necessity of costly \xXX representations.
         * 
         * The character array includes encoded bytes covering the entire range
         * of characters covered by the challenge, except for the space
         * character, which is checked for separately.  The covered range
         * starts with comma, and ends with capital Z (the call to `toupper`
         * above handles lowercase letters).  Any characters not supported are
         * represented by the "#" character, which is otherwise unused and is
         * explicitly checked for later.  Additionally, an explicit check is
         * done here for any character above 'Z', which is changed to the
         * equivalent of a "#" character.
         * 
         * The encoded byte is retrieved from this array using the value of
         * the current character minus 44 (since the first supported character
         * is ASCII 44 and index 0 in the array).  Finally, for the ASCII-only
         * version, the offset of 64 is added back in.
         */

        c - 35 ? W(c >> 5, c & 31) : 0;

        /**** OR, for the ASCII version ****/

        c - 99 ? W(c >> 5, c & 31) : 0;

        /* Here that explicit check for the "#" character, which, as
         * mentioned above, is for characters which will be ignored, because
         * they aren't supported.  If c is 35 (or 99 for the ASCII version),
         * then the expression before the ? evaluates to 0, or false, so the
         * expression after the : is evaluated.  Otherwise, the expression
         * before the ? is non-zero, thus true, so the expression before
         * the : is evaluated.
         *
         * This is equivalent to:
         *
         *     if(c != 35) // or 99, for the ASCII version
         *         W(c >> 5, c & 31);
         *
         * but is shorter by 2 characters.
         */

        putch(0);
        /* This will output to the screen a blank space.  Technically, it not
         * the same as a space character, but it looks like one, so I think I
         * can get away with it.  If a real space character is desired, this
         * must be changed to `putch(32);`, which adds one character to the
         * overall length.
    } /* end for loop, continue with the rest of the input string */
} /* end main */

Это превосходит все здесь, за исключением нескольких реализаций Python. Я продолжаю думать, что он не может быть короче, но потом я нахожу способ сбрить еще несколько персонажей. Если кто-нибудь может найти больше возможностей для улучшения, сообщите мне.

EDIT:

Я заметил, что, хотя эта процедура отклоняет любые недопустимые символы выше ASCII 44 (выводит только пустое пространство для каждого из них), оно не проверяет наличие недопустимых символов ниже этого значения. Чтобы проверить их, добавьте 5 символов в общую длину, изменив это:

...c>90?35:c-32?"...

:

...c-32?c>90|c<44?35:"...

Ответ 15

REBOL (118 символов)

Примерно 10-летняя реализация

foreach c ask""[l: index? find" etinamsdrgukwohblzfcpövxäqüyj"c while[l >= 2][prin pick"-."odd? l l: l / 2]prin" "]

Цитата из: http://www.rebol.com/oneliners.html

(никакие цифры и слова просто не разделены пробелами:/...)

Ответ 16

Python 2; 171 символ

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

for c in raw_input().lower():print"".join(".-"[int(d)]for d in bin(
('  etianmsurwdkgohvf_l_pjbxcyzq__54_3___2%7s16%7s7___8_90%12s?%8s.%29s,'
%(('',)*5)).find(c))[3:])or'/',

(добавленные новые строки могут быть удалены)

Или, если вы предпочитаете не использовать функцию bin() в 2.6, мы можем сделать это в 176:

for c in raw_input():C=lambda q:q>0and C(~-q/2)+'-.'[q%2]or'';print C(
(' etianmsurwdkgohvf_l_pjbxcyzq__54_3___2%7s16%7s7___8_90%12s?%8s.%29s,'%
(('',)*5)).find(c.lower()))or'/',

(опять же, добавленные новые строки могут быть удалены)

Ответ 17

Python (210 символов)

Это полное решение, основанное на Alec one

def e(l):
 i=(' etianmsurwdkgohvf_l_pjbxcyzq__54_3___2%7s16%7s7___8_90%12s?%8s.%29s,'%tuple('_'*5)).find(l.lower());v=''
 while i>0:v='-.'[i%2]+v;i=(i-1)/2
 return v or '/'
def enc(s):return ' '.join(map(e,s))

Ответ 18

C, 338 символов

338 с отступом и удалением всех удаляемых строк:

#define O putchar
#define W while
char*l="[email protected]@@@@[email protected]@FBdYcbcbSd[Kcd`\31(\b1g_<qCN:_'|\25D$W[QH0";
int c,b,o;
main(){
  W(1){
    W(c<32)
      c=getchar()&127;
    W(c>96)
      c^=32;
    c-=32;
    o=l[c/2]-64;
    b=203+(c&1?o>>3:0);
    o=c&1?o&7:o>>3;
    W(o>6)
      O(47),o=0;
    c/=2;
    W(c--)
      b+=(l[c]-64&7)+(l[c]-64>>3);
    b=(((l[b/7]<<7)+l[b/7+1])<<(b%7))>>14-o;
    W(o--)
      O(b&(1<<o)?46:45);
    O(32);
  }
}

Это не основано на древовидном подходе, который принимали другие люди. Вместо этого l сначала кодирует длины всех байтов между 32 и 95 включительно, два байта для символа. В качестве примера D - это... для длины 3 и E. для длины 1. Это закодировано как 011 и 001, давая 011001. Чтобы сделать больше символов кодируемыми и избегать экранов, к сумме добавляется 64, давая 1011001 - 89, ASCII Y. Символы без морса назначаются длиной 0. Вторая половина l (начиная с \031) - это биты самого кода Морзе, причем точка равна 1 и тире 0. Чтобы избежать перехода на высокий ASCII, эти данные кодируются 7 бит/байт.

Сначала код очищает c, затем выдает длину морса co), затем добавляет длины всех предыдущих символов для создания b, индекс бит в данные.

Наконец, он проходит через биты, печатает точки и тире.

Длина "7" используется как специальный флаг для печати a/при встрече с пробелом.

Вероятно, есть некоторые небольшие выгоды от удаления скобок, но я ухожу от некоторых лучших результатов, и я голоден, поэтому...

Ответ 19

С# Использование Linq (133 символа)

    static void Main()
    {
        Console.WriteLine(String.Join(" ", (from c in Console.ReadLine().ToUpper().ToCharArray()
                                            select m[c]).ToArray()));
    }

Хорошо, поэтому я обманул. Вам также нужно определить словарь следующим образом (не надо было подсчитывать символы, так как это ударяет меня из игры):

    static Dictionary<char, string> m = new Dictionary<char, string>() {
            {'A', ".-"},
            {'B', "-.."},
            {'C', "-.-."},
            {'D', "-.."},
            {'E', "."},
            {'F', "..-."},
            {'G', "--."},
            {'H', "...."},
            {'I', ".."},
            {'J', ".---"},
            {'K', "-.-"},
            {'L', ".-.."},
            {'M', "--"},
            {'N', "-."},
            {'O', "---"},
            {'P', ".--."},
            {'Q', "--.-"},
            {'R', ".-."},
            {'S', "..."},
            {'T', "-"},
            {'U', "..-"},
            {'V', "...-"},
            {'W', ".--"},
            {'X', "-..-"},
            {'Y', "-.--"},
            {'Z', "--.."},
            {'0', "-----"},
            {'1', ".----"},
            {'2', "..---"},
            {'3', "...--"},
            {'4', "....-"},
            {'5', "....."},
            {'6', "-...."},
            {'7', "--..."},
            {'8', "---.."},
            {'9', "----."},
            {' ', "/"},
            {'.', ".-.-.-"},
            {',', "--..--"},
            {'?', "..--.."},
        };

Тем не менее, может ли кто-то предоставить более сжатую реализацию С#, которая также так же легко понять и поддерживать как это?

Ответ 20

Perl, 206 символов, используя идею dmckee

Это больше, чем первая, которую я представил, но я все еще думаю, что это интересно. И/или ужасно. Я еще не уверен. Это использует идею кодирования dmckee, плюс пару других хороших идей, которые я видел вокруг. Первоначально я думал, что вещь "длина/смещение в фиксированной строке" не может вывести меньше данных, чем схема в моем другом решении, которая использует фиксированные два байта на char (и все эти байты для печати), Фактически мне удалось значительно уменьшить данные (один байт за char плюс четыре байта для хранения 26-битного шаблона, в который мы индексируем), но код, чтобы получить его снова, длиннее, несмотря на мои лучшие усилия по гольфу. (Менее сложный, ИМО, но дольше в любом случае).

Во всяком случае, 206 символов; новые строки являются съемными, кроме первого.

#!perl -lp
($a,@b)=unpack"b32C*",
"\264\202\317\0\31SF1\2I.T\33N/G\27\308XE0=\x002V7HMRfermlkjihgx\207\205";
$a=~y/01/-./;@m{A..Z,0..9,qw(. , ?)}=map{substr$a,$_%23,1+$_/23}@b;
$_=join' ',map$m{uc$_}||"/",/./g

Пояснение:

  • Есть две части данных. Первые четыре байта ("\264\202\317\0") представляют собой 32 бита кода Морзе ("--.-..-.-.-----.....--..--------"), хотя используются только первые 26 бит. Это "ссылочная строка".
  • Остальная часть строки данных сохраняет исходное положение и длина подстрок опорной строки, которые представляют каждый символ - один байт на символ, в порядке (А, В,... Z, 0, 1,... 9, ".", ",", "?" ). Значения кодируются как 23 * (длина - 1) + pos, и декодер отменяет это. Последняя стартовая позиция - это, конечно, 22.
  • Таким образом, распаковка делает половину работы по извлечению данных, а третья строка (как показано здесь) делает все остальное, теперь у нас есть хэш с $m{'a'} = '.-' et cetera, поэтому все, что осталось, это совпадение с символами введите их в хэш и отформатируйте вывод, который делает последняя строка... с некоторой помощью от shebang, которая сообщает perl удалить новую строку на входе, поместить строки ввода в $_ и когда код завершает работу, пишите $_ назад к выводу с добавлением новых строк.

Ответ 21

C89 (293 символа)

Исходя из некоторых других ответов.

EDIT: Сократить дерево (yay).

#define P putchar
char t['~']="~ETIANMSURWDKGOHVF~L~PJBXCYZQ~~54~3",o,q[9],Q=10;main(c){for(;Q;)t[
"&./7;=>KTr"[--Q]]="2167890?.,"[Q];while((c=getchar())>=0){c-=c<'{'&c>96?32:0;c-
10?c-32?0:P(47):P(10);for(o=1;o<'~';++o)if(t[o]==c){for(;o;o/=2)q[Q++]=45+(o--&1
);for(;Q;P(q[--Q]));break;}P(32);}}

Ответ 22

Здесь другой подход, основанный на работе dmckee, демонстрирует, насколько читаемым Python является:

Python

244 символа

def h(l):p=2*ord(l.upper())-88;a,n=map(ord,"AF__GF__]E\\E[EZEYEXEWEVEUETE__________CF__IBPDJDPBGAHDPC[DNBSDJCKDOBJBTCND`DKCQCHAHCZDSCLD??OD"[p:p+2]);return "--..--..-.-.-..--...----.....-----.-"[a-64:a+n-128]
def e(s):return ' '.join(map(h,s))

Ограничения:

  • Строка dmckee пропустила символ "Y", и я был слишком ленив, чтобы добавить его. Я думаю, вам просто нужно изменить "??" part и добавить "-" в конец второго строкового литерала
  • он не помещает '/' между словами; снова, ленивый

Поскольку правила, называемые наименьшим количеством символов, не менее байтов, вы можете сделать хотя бы одну из моих таблиц поиска меньше (наполовину), если вы захотите выйти за пределы печатных символов ASCII.

EDIT: Если я использую наивно выбранные символы Unicode, но просто сохраняю их в ASCII файле в исходном файле, он все равно становится короче, потому что декодер проще:

Python

240 символов

def h(l):a,n=divmod(ord(u'\x06_7_\xd0\xc9\xc2\xbb\xb4\xad\xa6\x9f\x98\x91_____\x14_AtJr2<s\xc1d\x89IQdH\x8ff\xe4Pz9;\xba\x88X_f'[ord(l.upper())-44]),7);return "--..--..-.-.-..--...----.....-----.-"[a:a+n]
def e(s):return ' '.join(map(h,s))

Я думаю, что это также делает программу более понятной.

Если вы сохранили это как UTF-8, я считаю, что программа будет содержать до 185 символов, что сделает ее самым коротким полным решением на Python и уступит только Perl.: -)

Ответ 23

Здесь третий, совершенно другой способ кодирования кода Морзе:

Python

232 символа

def d(c):
 o='';b=ord("Y_j_?><80 !#'/_____f_\x06\x11\x15\x05\x02\x15\t\x1c\x06\x1e\r\x12\x07\x05\x0f\x16\x1b\n\x08\x03\r\x18\x0e\x19\x01\x13"[ord(c.upper())-44])
 while b!=1:o+='.-'[b&1];b/=2
 return o
e=lambda s:' '.join(map(d,s))

Если вы можете найти способ сопоставить это с некоторыми наборами печатаемых символов, вы можете сохранить несколько символов. Это, вероятно, мое самое прямое решение, хотя я не знаю, является ли это наиболее читаемым.

ОК, теперь я потратил слишком много времени на это.

Ответ 24

Haskell

type MorseCode = String

program :: String
program = "__5__4H___3VS__F___2 UI__L__+_ R__P___1JWAE"
     ++ "__6__=B__/_XD__C__YKN__7_Z__QG__8_ __9__0 OMT "

decode :: MorseCode -> String
decode = interpret program
    where
    interpret         = head . foldl exec []
    exec xs       '_' = undefined : xs
    exec (x:y:xs)  c  = branch    : xs
        where
        branch (' ':ds) = c : decode ds
        branch ('-':ds) = x ds
        branch ('.':ds) = y ds
        branch []       = [c]

Например, decode "-- --- .-. ... . -.-. --- -.. ." возвращает "MORSE CODE".

Эта программа взята из отличной статьи Fun с кодом Морзе.

Ответ 25

PHP

Я изменил предыдущую запись PHP, чтобы быть немного более эффективным.:)

$a=array(32=>"/",44=>"--..--",1,".-.-.-",48=>"-----",".----","..---","...--","....-",".....","-....","--...","---..","----.",63=>"..--..",1,".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..");
foreach(str_split(strtoupper("hello world?"))as$k=>$v){echo $a[ord($v)]." ";}

Комодо говорит 380 символов на 2 строках - дополнительная строка предназначена только для чтения.; D Вмещенные 1s в массиве - это просто сохранить 2 байта, заполнив эту позицию массива данными вместо того, чтобы вручную перейти в позицию массива после этого.

Рассмотрим первое и второе. Разница отчетливо видна.:)

array(20=>"data",22=>"more data";
array(20=>"data",1,"more data";

Конечный результат, однако, в точности до тех пор, пока вы используете позиции массива, а не просматриваете содержимое, которое мы не делаем на этом поле для гольфа.

Конечный результат: 578 символов, до 380 (198 символов или ~ 34,26% экономии).

Ответ 26

Bash, a script, который я написал некоторое время назад (временная марка говорит в прошлом году), весом в 1661 персонаж. Просто для развлечения действительно:)

#!/bin/sh
txt=''
res=''
if [ "$1" == '' ]; then
    read -se txt
else
    txt="$1"
fi;
len=$(echo "$txt" | wc -c)
k=1
while [ "$k" -lt "$len" ]; do
    case "$(expr substr "$txt" $k 1 | tr '[:upper:]' '[:lower:]')" in
        'e')    res="$res"'.' ;;
        't')    res="$res"'-' ;;
        'i')    res="$res"'..' ;;
        'a')    res="$res"'.-' ;;
        'n')    res="$res"'-.' ;;
        'm')    res="$res"'--' ;;
        's')    res="$res"'...' ;;
        'u')    res="$res"'..-' ;;
        'r')    res="$res"'.-.' ;;
        'w')    res="$res"'.--' ;;
        'd')    res="$res"'-..' ;;
        'k')    res="$res"'-.-' ;;
        'g')    res="$res"'--.' ;;
        'o')    res="$res"'---' ;;
        'h')    res="$res"'....' ;;
        'v')    res="$res"'...-' ;;
        'f')    res="$res"'..-.' ;;
        'l')    res="$res"'.-..' ;;
        'p')    res="$res"'.--.' ;;
        'j')    res="$res"'.---' ;;
        'b')    res="$res"'-...' ;;
        'x')    res="$res"'-..-' ;;
        'c')    res="$res"'-.-.' ;;
        'y')    res="$res"'-.--' ;;
        'z')    res="$res"'--..' ;;
        'q')    res="$res"'--.-' ;;
        '5')    res="$res"'.....' ;;
        '4')    res="$res"'....-' ;;
        '3')    res="$res"'...--' ;;
        '2')    res="$res"'..---' ;;
        '1')    res="$res"'.----' ;;
        '6')    res="$res"'-....' ;;
        '7')    res="$res"'--...' ;;
        '8')    res="$res"'---..' ;;
        '9')    res="$res"'----.' ;;
        '0')    res="$res"'-----' ;;
    esac;
    [ ! "$(expr substr "$txt" $k 1)" == " " ] && [ ! "$(expr substr "$txt" $(($k+1)) 1)" == ' ' ] && res="$res"' '
    k=$(($k+1))
done;
echo "$res"

Ответ 27

C, 533 символа

Я получил совет от некоторых комментариев и переключился на stdin. Погибло еще около 70 символов.

#include <stdio.h>
#include <ctype.h>
char *u[36] = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."};
main(){
char*v;int x;char o;
do{
o = toupper(getc(stdin));v=0;if(o>=65&&o<=90)v=u[o-'A'];if(o>=48&&o<=57)v=u[o-'0'+26];if(o==46)v=".-.-.-";if(o==44)v="--..--";if(o==63)v="..--..";if(o==32)v="/";if(v)printf("%s ", v);} while (o != EOF);
}

Ответ 28

C89 (388 символов)

Это неполное, поскольку оно еще не обрабатывает запятую, полный цикл и запрос.

#define P putchar
char q[10],Q,tree[]=
"EISH54V 3UF    2ARL   + WP  J 1TNDB6=X/ KC  Y  MGZ7 Q  O 8  90";s2;e(x){q[Q++]
=x;}p(){for(;Q--;putchar(q[Q]));Q=0;}T(int x,char*t,int s){s2=s/2;return s?*t-x
?t[s2]-x?T(x,++t+s2,--s/2)?e(45):T(x,t,--s/2)?e(46):0:e(45):e(46):0;}main(c){
while((c=getchar())>=0){c-=c<123&&c>96?32:0;if(c==10)P(10);if(c==32)P(47);else
T(c,tree,sizeof(tree)),p();P(' ');}}

Обернута для удобочитаемости. Требуются только две из строк (один для #define, один за другим, который может быть пробелом). Я добавил несколько нестандартных символов, но не добавил не-7-битные.

Ответ 29

C (381 символ)

char*p[36]={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."};
main(){int c;while((c=tolower(getchar()))!=10)printf("%s ",c==46?".-.-.-":c==44?"--..--":c==63?"..--..":c==32?"/":*(p+(c-97)));}

Ответ 30

C, 448 байтов с использованием аргументов cmdline:

char*a[]={".-.-.-","--..--","..--..","/",".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."},*k=".,? ",*s,*p,x;main(int _,char**v){for(;s=*++v;putchar(10))for(;x=*s++;){p=strchr(k,x);printf("%s ",p?a[p-k]:isdigit(x)?a[x-18]:isalpha(x=toupper(x))?a[x-61]:0);}}

C, 416 байт с использованием stdin:

char*a[]={".-.-.-","--..--","..--..","/",".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."},*k=".,? ",*p,x;main(){while((x=toupper(getchar()))-10){p=strchr(k,x);printf("%s ",p?a[p-k]:isdigit(x)?a[x-18]:isalpha(x)?a[x-61]:0);}}