将string转换成莫尔斯电码

挑战

字符计数的最短代码,它将只使用字母字符(大写和小写),数字,逗号,句号和问号input一个string,并返回莫尔斯码中的string表示forms。 莫尔斯电码的输出应该包含一个长音(AKA'dah')的短划线( - ,ASCII 0x2D)和短音(AKA'dit')的一个点( . ,ASCII 0x2E)。

每个字母应该用空格分隔( ' ' ,ASCII 0x20),每个字应该用正斜杠( / ,ASCII 0x2F)分隔。

莫尔斯电码表:

替代文字http://liranuna.com/junk/morse.gif

testing用例:

 Input: Hello world Output: .... . .-.. .-.. --- / .-- --- .-. .-.. -.. 

 Input: Hello, Stackoverflow. Output: .... . .-.. .-.. --- --..-- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- .-.-.- 

代码数包括input/​​输出(即完整的程序)。

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);} 

通过将来自whilefor循环的逻辑组合成一个for循环,并通过将cvariables的声明作为input参数移动到main定义中,我再多出几个字符。 后一种技术是我从另一个挑战中借用的 。


对于那些试图使用GCC或仅使用ASCII编辑器来validation程序的人,您可能需要以下稍长的版本:

 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个字符(体重相当庞大),原因如下:

  • +4: getchar()putchar()而不是不可移植的getch()putch()
  • +6:两个字符而不是非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);} 

在我看来,这个最新的版本也更具视觉吸引力。 不,这不是可移植的,它不再受到保护,不受外界的限制。 它也有一个非常糟糕的用户界面,采取逐字符input,并将其转换为莫尔斯电码,并没有退出条件(你必须按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'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 */ ); } 

代码中长string中的每个字符都包含一个文本字符的编码莫尔斯电码。 编码字符的每一位代表破折号或点。 一个代表破折号,零代表一个点。 最低有效位表示莫尔斯电码中的第一个短划线或点。 最后的“保护”位决定了代码的长度。 也就是说,每个编码字符中的最高一位表示代码结束,而不是打印。 没有这个守卫位,尾随点的字符不能正确打印。

例如,摩尔斯电码中的字母“L”是“ .-.. ”。 为了用二进制表示,我们需要一个0,1和2个0,从最低有效位开始:0010。对于一个保护位,再加一个1,并且我们有我们的编码莫尔斯电码:10010或者十进制18.添加+34偏移量以获得52,即字符“4”的ASCII值。 所以编码的字符数组有一个“4”作为第33个字符(索引32)。

这种技术与ACoolie , Strager (2) , Miles's , pingw33n , Alec和Andrea的解决scheme中的字符编码类似,但是稍微简单一些,每位只需要一个操作(移位/分割),而不是两个/划分和递减)。

编辑:
仔细阅读其余的实现,我发现Alec和Anon在我之前提出了这种编码scheme – 使用guard位。 Anon的解决scheme是特别有趣的,使用Python的bin函数,并用[3:]去掉"0b"前缀和保护位,而不像Alec和我做的那样循环,移位和移位。

作为奖励,这个版本还处理连字符( -....- ),斜线( -..-. ),冒号( ---... ),分号( ---... -.-.-. ),等号( -...- )和符号( .--.-. )。 只要允许8位字符,这些字符就不需要额外的代码字节来支持。 这个版本没有更多的字符可以被支持,而不会增加代码的长度(除非摩尔斯码大于/小于符号)。

因为我发现旧的实现仍然很有趣,文本有一些适用于这个版本的警告,我已经离开了这篇文章的以前的内容下面。


好吧,据推测,用户界面可以吸,对吧? 所以,从strager借用,我已经取代了gets() ,它提供了缓冲,回显线路input, getch() ,它提供了无缓冲的,非查询的字符input。 这意味着您键入的每个字符都会立即转换成屏幕上的摩尔斯码。 也许这很酷。 它不再适用于标准input或命令行参数,但它非常小。

尽pipe如此,我仍然保留下面的旧代码以供参考。 这是新的。

新的代码,边界检查,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);} 

input打破循环并退出程序。

新的代码,没有边界检查,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);} 

这是基于安德烈的Python的答案 ,使用相同的技术来产生摩尔斯电码的答案。 但是我不是一个接一个地存储可编码字符,而是寻找它们的索引,我一个接一个地存储这些索引,然后用字符(类似于我之前的回答 )来查找它们。 这可以防止靠近结束处的较长的间隙,这为较早的实现者造成了问题。

和以前一样 ,我使用了一个大于127的字符。将它转换为ASCII仅添加3个字符。 长string的第一个字符必须replace为\x9C 。 这次偏移是必要的,否则大量的字符在32以下, 必须用转义码表示。

同前面一样,处理命令行参数而不是stdin会添加2个字符,而在代码之间使用实际空格字符会添加1个字符。

另一方面,这里的其他一些例程并不涉及[0.0-9 \?A-Za-z]的可接受范围之外的input。 如果从这个例程中删除了这样的处理,那么可以删除19个字符,使得总共低至177个字符。 但是,如果这样做了,并且无效的input被馈送到这个程序,它可能会崩溃并烧毁。

这种情况下的代码可以是:

 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);} 

使用莫尔斯电码字体 ?

 Console.Write(params[0]); 

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 

说明:

  1. 提取莫尔斯词典。 每个符号由两个字符定义,可以是文字点或破折号,也可以是对另一个定义字符值的引用。 E和T包含虚拟字符以避免解码器的去相关; 我们稍后会删除它们。
  2. 读取并格式化input。 "Hello world"变成"HELLO / WORLD"
  3. 下一步取决于input和输出字典是不同的,所以把input中的点变成一个未使用的字符(竖线, |
  4. 将input中出现在morse字典中的字符replace为字典中的值,直到不发生replace。
  5. 删除步骤1中提到的虚拟字符。
  6. 打印输出。

在最终版本中,字典经过优化以提高运行效率:

  • 所有一个符号字符(E和T)和两个符号字符(A,I,M和N)直接定义并解码一次。
  • 所有的三个符号字符都是用两个符号字符和一个文字符号来定义的,两次解码。
  • 所有的四符号字符都是用两个两符号字符来定义的,两次解码就是三次replace。
  • 五个和六个符号字符(数字和标点符号)分三次解码,分别replace四次或五次。

由于打高尔夫球的代码只能取代每个循环中的一个字符(为了保存一个字符的代码!),循环次数限制为input长度的五倍(如果仅使用字母表,则为input长度的三倍)。 但是通过在s///操作中添加一个g ,循环次数限制为三次(如果仅使用字母,则为两次)。

示例转换:

 Hello 123 HELLO / 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|':<.$402&9/6)(18?,*%+3-;=>"[ord(c)-44])-34)[3:].translate(" "*47+"/.-"+" "*206), 

使用类似的数据打包到P Daddy的C实现 ,但不以相反的顺序存储位,并使用bin()来提取数据而不是算术。 还要注意,使用不等式检测空间; 它认为每个字符“不到逗号”是一个空间。

Python循环,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, 

我正在为这些符号编写一个紧凑的代码,但是我不知道是否比已经使用的隐式树更好,所以我在这里提出编码,以防其他人可以使用它。

考虑一下string:

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

其中包含所有需要的序列作为子string。 我们可以按照这样的偏移和长度编码符号:

  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爸爸发现这个技巧的一个更短的版本 (我现在可以看到至less一些冗余),并做了一个很好的C实现。 亚历克做了第一个(越野车和不完整)版本的python实现 。 霍布斯做了一个非常紧凑的perl版本 ,我根本不懂。

J,124 130 134个字符

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

J击败C! 真棒!

用法:

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

Python 3 One Liner: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())) 

(将转换表编码为unicode代码点,工作正常,在我的Windows Vista机器上的testing中,它们显示的很好。

删除一些不必要的空格和括号(使列表comps gen exps)删除到184个字符。

再次编辑:在我看到其他答案之前,我甚至不知道还有更多的空间被删除 – 所以下降到176。

使用''.join代替''.join再分别编辑空格来编辑172(woo woo!)。 (咄!)

C#266字符

将131 char C解决scheme转换为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) })); } 

Golfscript – 106个字符 – 没有有趣的火焰:)

input结尾的换行符不被支持,所以使用这样的东西

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

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

字母是一种特殊情况,并转换为小写字母,并以二进制位置sorting。
其他的一切都是由翻译表完成的

python

不完整的解决scheme,但也许有人可以做出完整的解决scheme。 不处理数字或标点符号,但重量只有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个字符)

另一种基于树的解决scheme。

 #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?\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个字符的范围
  • 所以string文字将沿着这些行编码一个表格

还有一点,但这是主要的。 逗号,句号和空格不在0..Z的范围内,所以它们被“匹配”特别处理。 在表中使用0..Z(如';')范围内的一些“未使用”字符作为本身不是莫尔斯“字母”的其他莫尔斯翻译的后缀。

这是我在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个字符。 它将从命令行读取input,每次一行,并将相应的输出发送回输出stream。 压缩版本在下面,只有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);}} 

这需要从stdininput。 从命令行input添加2个字符。 代替:

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

你得到:

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

我在127以上的字符上使用了Windows-1252的代码页,我不确定他们会在其他人的浏览器中出现。 我注意到,至less在我的浏览器(Google Chrome)中,两个字符(“@”和“i”之间)没有出现。 但是,如果您从浏览器中复制并粘贴到文本编辑器中,它们确实会显示出来,尽pipe只是一些小框。

它可以转换为仅ASCII,但是这增加了24个字符,增加了字符数到257.为此,我首先偏移string中的每个字符-64,最大限度地减less字符数大于127.然后我用\x XX字符replace必要的地方。 它改变了这一点:

 ...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'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实现之外,这里比所有的东西都要好。 我一直认为它不能缩短,但是我find了一些方法来削减更多的字符。 如果有人可以find更多的改善空间,让我知道。

编辑:

我注意到,虽然这个例程拒绝了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? ll: l / 2]prin" "] 

引自: http : //www.rebol.com/oneliners.html

(尽pipe没有数字,单词之间用双空格隔开:/ …)

Python(210个字符)

这是基于亚历克的一个完整的解决scheme

 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 chars

338 with indentation and all removable linebreaks removed:

 #define O putchar #define W while char*l="x@@@@@ppmmmmm@@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); } } 

This isn't based on the tree approach other people have been taking. Instead, l first encodes the lengths of all bytes between 32 and 95 inclusive, two bytes to a character. As an example, D is -.. for a length of 3 and E is . for a length of 1. This is encoded as 011 and 001, giving 011001. To make more characters encodable and avoid escapes, 64 is then added to the total, giving 1011001 – 89, ASCII Y. Non-morse characters are assigned a length of 0. The second half of l (starting with \031 ) are the bits of the morse code itself, with a dot being 1 and a dash 0. To avoid going into high ASCII, this data is encoded 7 bits/byte.

The code first sanitises c , then works out the morse length of c (in o ), then adds up the lengths of all the previous characters to produce b , the bit index into the data.

Finally, it loops through the bits, printing dots and dashes.

The length '7' is used as a special flag for printing a / when encountering a space.

There are probably some small gains to be had from removing brackets, but I'm way off from some of the better results and I'm hungry, so…

C# Using Linq (133 chars)

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

OK, so I cheated. You also need to define a dictionary as follows (didn't bother counting the chars, since this blows me out of the game):

  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', "----."}, {' ', "/"}, {'.', ".-.-.-"}, {',', "--..--"}, {'?', "..--.."}, }; 

Still, can someone provide a more concise C# implementation which is also as easy to understand and maintain as this?

Perl, 206 characters, using dmckee's idea

This is longer than the first one I submitted, but I still think it's interesting . And/or awful. I'm not sure yet. This makes use of dmckee's coding idea, plus a couple other good ideas that I saw around. Initially I thought that the "length/offset in a fixed string" thing couldn't come out to less data than the scheme in my other solution, which uses a fixed two bytes per char (and all printable bytes, at that). I did in fact manage to get the data down to considerably less (one byte per char, plus four bytes to store the 26-bit pattern we're indexing into) but the code to get it out again is longer, despite my best efforts to golf it. (Less complex, IMO, but longer anyway).

Anyway, 206 characters; newlines are removable except the first.

 #!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 

说明:

  • There are two parts to the data. The first four bytes ( "\264\202\317\0" ) represent 32 bits of morse code ( "--.-..-.-.-----.....--..--------" ) although only the first 26 bits are used. This is the "reference string".
  • The remainder of the data string stores the starting position and length of substrings of the reference string that represent each character — one byte per character, in the order (A, B, … Z, 0, 1, … 9, ".", ",", "?"). The values are coded as 23 * (length – 1) + pos, and the decoder reverses that. The last starting pos is of course 22.
  • So the unpack does half the work of extracting the data and the third line (as viewed here) does the rest, now we have a hash with $m{'a'} = '.-' et cetera, so all there is left is to match characters of the input, look them up in the hash, and format the output, which the last line does… with some help from the shebang, which tells perl to remove the newline on input, put lines of input in $_ , and when the code completes running, write $_ back to output with newlines added again.

Python 2; 171 characters

Basically the same as Andrea's solution , but as a complete program, and using stupid tricks to make it shorter.

 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'/', 

(the added newlines can all be removed)

Or, if you prefer not to use the bin() function in 2.6, we can get do it in 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'/', 

(again, the added newlines can all be removed)

C89 (293 characters)

Based off some of the other answers.

EDIT: Shrunk the tree (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);}} 

Here's another approach, based on dmckee's work, demonstrating just how readable Python is:

python

244 characters

 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's string missed the 'Y' character, and I was too lazy to add it. I think you'd just have to change the "??" part, and add a "-" at the end of the second string literal
  • it doesn't put '/' between words; again, lazy

Since the rules called for fewest characters , not fewest bytes , you could make at least one of my lookup tables smaller (by half) if you were willing to go outside the printable ASCII characters.

EDIT: If I use naïvely-chosen Unicode chars but just keep them in escaped ASCII in the source file, it still gets a tad shorter because the decoder is simpler:

python

240 characters

 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)) 

I think it also makes the intent of the program much clearer.

If you saved this as UTF-8, I believe the program would be down to 185 characters, making it the shortest complete Python solution, and second only to Perl. 🙂

Here's a third, completely different way of encoding morse code:

python

232 characters

 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)) 

If you can figure out a way to map this onto some set of printable characters, you could save quite a few characters. This is probably my most direct solution, though I don't know if it's the most readable.

OK, now I've wasted way too much time on this.

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] 

For example, decode "-- --- .-. ... . -.-. --- -.. ." returns "MORSE CODE" .

This program is from taken from the excellent article Fun with Morse Code .

PHP

I modified the previous PHP entry to be slightly more efficient. 🙂

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

Komodo says 380 characters on 2 lines – the extra line is just for readability. ;D The interspersed 1s in the array is just to save 2 bytes by filling that array position with data instead of manually jumping to the array position after that.

Consider the first vs. the second. The difference is clearly visible. 🙂

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

The end result, however, is exactly as long as you use the array positions rather than loop through the contents, which we don't do on this golf course.

End result: 578 characters, down to 380 (198 characters, or ~34.26% savings).

Bash , a script I wrote a while ago (time-stamp says last year) weighing in at a hefty 1661 characters. Just for fun really 🙂

 #!/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" 

C89 (388 characters)

This is incomplete as it doesn't handle comma, fullstop, and query yet.

 #define P putchar char q[10],Q,tree[]= "EISH54V 3UF 2ARL + WP J 1TNDB6=X/ KC Y MGZ7 QO 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?*tx ?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(' ');}} 

Wrapped for readability. Only two of the linebreaks are required (one for the #define, one after else, which could be a space). I've added a few non-standard characters but didn't add non-7-bit ones.

C, 533 characters

I took advice from some comments and switched to stdin. Killed another 70 characters roughly.

 #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 characters)

 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 bytes using cmdline arguments:

 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[pk]:isdigit(x)?a[x-18]:isalpha(x=toupper(x))?a[x-61]:0);}} 

C , 416 bytes using stdin:

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