Преобразование строки в код Морзе [закрыто]
вызов
самый короткий код по количеству символов, который будет вводить строку, используя только алфавитные символы (верхний и нижний регистр), цифры, запятые, точки и вопросительный знак, и возвращает представление строки в коде Морзе.
Вывод кода Морзе должен состоять из тире (-
, ASCII 0x2D) для длинного звукового сигнала (он же "dah") и точки (.
, ASCII 0x2E) для короткого звукового сигнала (он же 'dit').
каждая буква должна быть разделена пробелом (' '
, ASCII 0x20), и каждое слово должно быть разделено косой чертой (/
, ASCII 0x2F).
таблица азбуки Морзе:
alt текст http://liranuna.com/junk/morse.gif
тестовые случаи:
Input:
Hello world
Output:
.... . .-.. .-.. --- / .-- --- .-. .-.. -..
Input:
Hello, Stackoverflow.
Output:
.... . .-.. .-.. --- --..-- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- .-.-.-
количество кодов включает вход / выход (то есть полную программу).
30 ответов
C (131 символ)
да 131!
main(c){for(;c=c?c:(c=toupper(getch())-32)?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+-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-only вам может потребоваться следующая, немного более длинная версия:
main(c){for(;c=c?c:(c=toupper(getchar())-32)?c<0?1:
"\x95#\x8CKa`^ZRBCEIQiw#S#nx(37+-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
является необязательным. The -funsigned-char
необходимо, хотя, Или вы получите мусор для запятой и полный остановка.
135 символов
c;main(){while(c=toupper(getch()))for(c=c-32?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+-2&@/4)'18=,*%.:0;?5"
[c-44]-34:-3;c;c/=2)putch(c/2?46-c%2:0);}
на мой взгляд, эта последняя версия намного более визуально привлекательна. И нет, он не портативный, и он больше не защищен от входа за пределы. Он также имеет довольно плохой пользовательский интерфейс, принимая символьный ввод и преобразование его в код Морзе и имея нет условие выхода (вы должны ударить Ctrl+перерыв). Но портативный, надежный код с хорошим интерфейсом не был требование.
краткое-как-возможное объяснение кода следует:
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+-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's very convenient that the three characters
* we need for this exercise are all consecutive.
*/
: 0 /* we're at the guard bit, output blank space */
);
}
каждый символ в длинной строке кода содержит кодированный код Морзе для одного текстового символа. Каждый бит закодированного символа представляет собой тире или точку. Единица представляет тире, а ноль-точку. Наименее значимый бит представляет собой первую черточку или точку в коде Морзе. Последний бит "guard" определяет длину кода. То есть самый высокий бит в каждом закодированном символе представляет собой конец кода и не печатается. Без этого защитного бита символы с конечными точками не могли быть напечатаны правильно.
например, буква " L "означает".-..
" азбукой Морзе. Чтобы представить это в двоичном формате, нам нужны 0, 1 и еще два 0, начиная с наименее значимого бита: 0010. Поставьте еще один 1 на охранный бит, и у нас есть код Морзе: 10010, или decimal 18. Добавьте смещение +34, чтобы получить 52, которое значение ASCII символа '4'. Таким образом, кодированный массив символов имеет " 4 " в качестве 33-го символа (индекс 32).
этот метод похож на тот, который используется для кодирования символов в ACoolie это!--47-->, strager это(2), Майлза, pingw33n это, Алек и Андреа решения, но немного проще, требуя только одной операции на бит (сдвиг / деление), а не два (сдвиг/деление и уменьшение).
EDIT:
Читая остальные реализации, я вижу, что Алек и Анон придумал эту схему кодирования-используя бит guard-до того, как я это сделал. Решение Anon особенно интересно, используя Pythonbin
функция и снятие"0b"
префикс и охранник чуть с[3:]
, а не зацикливание, андинг, и перемещается, как мы с Алеком.
в качестве бонуса, эта версия также работает с дефисом (-....-
), Слэш (-..-.
), двоеточие (---...
), точка с запятой (-.-.-.
), равно (-...-
), и знак (.--.-.
). Пока разрешены 8-разрядные символы, эти символы не требуют дополнительных байтов кода для поддержки. Больше символов не может поддерживаться с этой версией без добавления длины кода (если нет кодов Морзе для большего/меньшего, чем знаки.)
поскольку я нахожу старые реализации все еще интересными, и текст имеет некоторые оговорки, применимые к этой версии, я оставил предыдущее содержание этого сообщения ниже.
хорошо, предположительно, пользовательский интерфейс может сосать, верно? Итак, заимствование из strager, Я заменил gets()
, который обеспечивает буферизованный, вторящий линейный вход, с getch()
, который обеспечивает unbuffered, unechoed ввод символов. Это означает, что каждый персонаж вы тип немедленно переводится в азбуку Морзе на экране. Может, это и круто. Он больше не работает ни с 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+;79-@6=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+;79-@6=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+;79-@6=0/8?F31,2:4BDE"[c-44]-42):
putch(47),putch(0);}
это основано на ответ питона Андреа, используя ту же технику для генерации кода Морзе, что и в этом ответе. Но вместо того, чтобы хранить кодируемые символы один за другим и находить их индексы, я хранил индексы один за другим и искал их по символам (аналогично мой предыдущий ответ). Это предотвращает длинные пробелы в конце, которые вызвали проблемы для более ранних исполнителей.
As до, я использовал символ, который больше 127. Преобразование его в ASCII-добавляет только 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+;79-@6=0/8?F31,2:4BDE"
[toupper(*p)-44]-42):putch(47),putch(0);}
Perl, 170 символов (с небольшой помощью совершенного гольфиста mauke
). Обернутый для ясности; все newlines съемны.
$_=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
объяснение:
- извлеките словарь Морзе. Каждый символ определяется в терминах двух символов, которые могут быть либо буквальными точками или тире, либо ссылкой на значение другого определенного символа. Е и Т содержат манекен chars, чтобы избежать desyncing декодер; мы будем вынуждены удалить их позже.
- чтение и форматирование вход.
"Hello world"
становится"H E L L O / W O R L D"
- следующий шаг зависит от того, что входные и выходные словари различны, поэтому поверните точки На входе в неиспользуемый символ (вертикальная полоса,
|
) - замените любой символ во входных данных, который происходит в словаре Морзе, его значением в словаре, пока не произойдет замены.
- удалите фиктивный символ, упомянутый в шаге 1.
- печати.
в финальной версии словарь оптимизирован для эффективности выполнения:
- все односимвольные символы (E и T) и двухсимвольные символы (A, I, M и N) определяются напрямую и декодируются за один проход.
- все трехсимвольные символы определяются в терминах двухсимвольного символа и буквального символа, декодирование в два прохода.
- все четырехсимвольные символы определяются в терминах двух двухсимвольных символов, декодирование в два прохода с тремя замены.
- пяти - и шестизначные символы (цифры и знаки препинания) декодируются за три прохода, с четырьмя или пятью заменами соответственно.
поскольку код golfed заменяет только один символ за цикл (чтобы сохранить один символ кода!) количество циклов ограничено пятикратной длиной входного сигнала (в три раза больше длины входного сигнала, если используется только алфавит). Но, добавив g
до s///
операция, количество циклов ограничено тремя (два, если используется только алфавит).
пример преобразования:
Hello 123
H E L L O / 1 2 3
II .] AI AI M- / AO UM SM
.... . .-.. .-.. --- / .-M- .A-- I.--
.... . .-.. .-.. --- / .---- ..--- ...--
понимание списка Python, 159-символьный однострочный
for c in raw_input().upper():print c<","and"/"or bin(ord("•ƒwTaQIECBRZ^`šŒ#S#n|':<.2&9/6)(18?,*%+3-;=>"[ord(c)-44])-34)[3:].translate(" "*47+"/.-"+" "*206),
использует аналогичную упаковку данных для P папины реализации C, но не хранит биты в обратном порядке и использует bin()
для извлечения данных, а не арифметика. Обратите внимание также, что пробелы обнаруживаются с использованием неравенства; он считает, что каждый символ "меньше запятой" является пробелом.
Python for
loop, 205 символов, включая newlines
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,
я возился с компактным кодированием символов, но я не вижу, становится ли лучше, чем уже используемые неявные деревья, поэтому я представляю кодирование здесь, Если кто-то еще может его использовать.
рассмотрим строку:
--..--..-.-.-..--...----.....-----.--/
, который содержит все необходимые последовательности в качестве подстроки. Мы!--7-- > мог бы код символов по смещению и длине, как это:
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 папа нашел более короткую версию этого трюка (и теперь я вижу, по крайней мере, некоторую избыточность здесь) и сделал хорошую реализацию C. Алек сделал реализацию python С первой (багги и неполной) версией. Хоббс сделал довольно компактную версию perl этого я совсем не понимаю.
J, 124 130 134 символы
'.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`dfggggggg-@B4*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper
J бьет C! Потрясающе!
использование:
'.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`dfggggggg-@B4*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper 'Hello World'
.... . .-.. .-.. --- / .-- --- .-. .-.. -..
'.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.></.40-~a.i.')}ggWOKIHX`dfggggggg-@B4*:68,?5</.7>E20+193ACD'{~0>.45-~a.i.toupper 'Hello, Stackoverflow.'
.... . .-.. .-.. --- .-.-.- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- --..--
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 (Ву-Ву!) с помощью ' '.присоединяйтесь вместо ".соедините и сделайте пробелы отдельно. (да!)
C# 266 символов
решение 131 char C, переведенное на 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+-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+-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) }));
}
Golfscript-106 символов - нет смешных символов:)
новая строка в конце ввода не поддерживается, поэтому используйте что-то вроде этого
echo -n Hello, Stackoverflow| ../golfscript.rb morse.gs
' '/{{.32|"!etianmsurwdkgohvf!l!pjbxcyzq"?)"UsL?/'#! 08<>"@".,?0123456789"?=or
2base(;>{'.-'\=}%' '}%}%'/'*
буквы являются частным случаем и преобразуются в нижний регистр и упорядочиваются в двоичных позициях.
Все остальное делается с помощью таблицы переводов
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))
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));}}
могут быть ошибки в исходном дереве, потому что Википедия кажется, это неправильно или, может быть, я чего-то недопонимаю.
F#, 256 символов
let rec D i=if i=16 then" "else
let x=int"U*:+F8c]uWjGbJ0-0Dnmd0BiC5?o`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) - это все "printable" и может служить как этот ряд 86 char
- таким образом, строковый литерал кодирует таблицу вдоль этих строк
есть немного больше, но это суть. Запятая, точка и Пробел не находятся в диапазоне 0..Z таким образом, они обрабатываются специально "матчем". Некоторые "неиспользуемые" символы в диапазоне 0..Z (like ';') используются в таблице в качестве суффиксов других переводов Морзе, которые сами по себе не являются буквами Морзе.
вот мой вклад в качестве консольного приложения в 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
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, но это добавляет 24 символа, увеличивая количество символов до 257. Для этого я сначала смещаю каждый символ в строке на -64, минимизируя количество символов, которое больше 127. Тогда я заменяю \x
XX символ убегает, когда это необходимо. Это меняет следующее:
...c>90?35:c-32?"È#À#¶µ´³²±°¹¸·#####Ê#@i Že‘J•aEAv„…`q!j“d‰ƒˆ"[c-44]:63;
c-35?W(...
to это:
...c>90?99:c-32?"\x88#\x80#vutsrqpyxw#####\x8A#PA)\xE0N%Q\nU!ODE 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#PA)\xE0N%Q\nU!ODE 1\xE1"
"*S$ICH"[c - 44] + 64 : 63;
/* Here's 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's 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's 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:"...
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
(нет цифр, хотя и слова просто разделены двойными пробелами :/ ...)
Python (210 символов)
Это полное решение, основанное на Алекодин
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))
C, 338 символов
338 с отступом и все съемные linebreaks удалены:
#define O putchar
#define W while
char*l="x@@@@@ppmmmmm@@FBdYcbcbSd[Kcd`(\b1g_<qCN:_'|D$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 и Е есть . для длины 1. Это кодируется как 011 и 001, давая 011001. Чтобы сделать больше символов encodable и избежать escapes, 64 затем добавляется к общей сумме, давая 1011001-89, ASCII Y. символам без Морзе присваивается длина 0. Вторая половина l
(начиная с 1
) - это биты самого кода Морзе, с точкой 1 и тире 0. Чтобы избежать перехода в высокий ASCII, эти данные кодируются 7 бит / байт.
код первой дезинфекции c
, затем вычисляет длину Морзе c
(in o
), затем добавляет длины всех предыдущих символов для создания b
, битовый индекс в данные.
наконец, он проходит через биты, печатая точки и тире.
длина ' 7 ' используется в качестве специального флага для печати a / при встрече с пробелом.
вероятно, есть некоторые небольшие выгоды от удаления скобок, но я далек от некоторых лучших результатов, и я голоден, поэтому...
C# с помощью 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', "----."},
{' ', "/"},
{'.', ".-.-.-"},
{',', "--..--"},
{'?', "..--.."},
};
тем не менее, может ли кто-то предоставить более краткую реализацию C#, которая также проста в понимании и обслуживании?
Perl, 206 символов, используя идею dmckee
это дольше, чем первый, который я представил, но я все еще думаю, что это интересные. И/или ужасно. Я пока не уверен. Это использует идею кодирования dmckee, а также пару других хороших идей, которые я видел вокруг. Первоначально я думал, что" длина/смещение в фиксированной строке " не может выйти на меньшее количество данных, чем схема в моем другом решении, которая использует фиксированные два байта на char (и все печатаемые байты, при этом). На самом деле мне удалось получить данные значительно меньше (один байт на char, плюс четыре байта для хранения 26-битного шаблона, в который мы индексируем), но код, чтобы получить его снова, длиннее, несмотря на мои усилия по гольфу. (Менее сложный, ИМО, но все равно дольше).
в любом случае, 206 символов; новые строки являются съемными, кроме первого.
#!perl -lp
($a,@b)=unpack"b32C*",
"427SF1I.TN/G8XE0=\x002V7HMRfermlkjihgx75";
$a=~y/01/-./;@m{A..Z,0..9,qw(. , ?)}=map{substr$a,$_%23,1+$_/23}@b;
$_=join' ',map$m{uc$_}||"/",/./g
объяснение:
- есть две части данных. Первые четыре байта (
"427"
) представляют 32 бита кода Морзе ("--.-..-.-.-----.....--..--------"
), хотя используются только первые 26 бит. Это "привязка". - остальная часть строки данных хранит начальную позицию и длину подстрок ссылочной строки, которые представляют каждый символ -- один байт на символ, в порядке (A, B,... Z, 0, 1,... 9, ".", ",", "?"). Значения кодируются как 23 * (длина-1) + pos, и декодер отменяет это. Конечно, последний стартовый pos 22.
- таким образом, распаковка делает половину работы по извлечению данных, а третья строка (как показано здесь) делает все остальное, теперь у нас есть хэш с
$m{'a'} = '.-'
и т. д., Поэтому все, что осталось, - это сопоставить символы ввода, найти их в хэше и отформатировать вывод, что делает последняя строка... с некоторой помощью shebang, который говорит perl удалить новую строку на входе, поместите строки ввода в$_
, и когда код завершит работу, напишите$_
назад к выходу с снова добавлены новые строки.
Python 2; 171 символов
в основном то же самое, что Андреа, но как полная программа, и с помощью глупых трюков, чтобы сделать его короче.
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'/',
(добавленные новые строки могут быть удалены)
или, если вы предпочитаете не использовать
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);}}
вот еще один подход, основанный на работе 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", и я был слишком ленив, чтобы добавить его. Я думаю, тебе просто нужно изменить "??"часть и добавьте" - " в конце второго строкового литерала
- он не ставит '/' между словами; Опять же, ленивый
С правила требовали наименьшего символы не меньше байт, вы могли бы сделать хотя бы одну из моих таблиц поиска меньше (наполовину), если бы Вы были готовы выйти за пределы печатаемых символов ASCII.
EDIT: если я использую наивно выбранные символы Юникода, но просто сохраняю их в Escape 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. :-)
вот третий, совершенно другой способ кодирования кода Морзе:
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))
Если вы можете найти способ отобразить это на некоторый набор печатаемых символов, вы можете сохранить довольно много символов. Это, наверное, мой самый прямые решение, хотя я не знаю, является ли оно наиболее читаемым.
хорошо, теперь я впустую путь на это слишком много времени.
Хаскелл
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"
.
эта программа взята из отличной статьи весело с азбукой Морзе.
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 строки - лишние строки только для чтения. ;Д Чередующиеся 1s в массиве-это просто сохранить 2 байта, заполнив эту позицию массива данными вместо того, чтобы вручную прыгать в позицию массива после этого.
рассмотрим первый и второй. Разница хорошо видна. :)
array(20=>"data",22=>"more data";
array(20=>"data",1,"more data";
конечный результат, однако, ровно до тех пор, пока вы используете позиции массива, а не петлю через содержимое, чего мы не делаем на этом поле для гольфа.
конечный результат: 578 символов, до 380 (198 символов, или ~34.26% экономии).
Баш, сценарий, который я написал некоторое время назад (отметка времени говорит в прошлом году) весом в здоровенных 1661 символов. Просто для удовольствия :)
#!/bin/sh
txt=''
res=''
if [ "" == '' ]; then
read -se txt
else
txt=""
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"
C89 (388 символов)
это неполное поскольку он еще не обрабатывает запятую, fullstop и запрос.
#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-битные.
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);
}
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)));}
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);}}