Convertir une chaîne en code Morse

Le défi

Le code le plus court par nombre de caractères, qui entrera une chaîne en utilisant uniquement des caractères alphabétiques (majuscules et minuscules), des nombres, des virgules, des points et un point d’interrogation, et retournera une représentation de la chaîne en code Morse. La sortie du code Morse doit comporter un tiret ( - , ASCII 0x2D) pour un bip long (AKA ‘dah’) et un point ( . , ASCII 0x2E) pour le bip court (AKA ‘dit’).

Chaque lettre doit être séparée par un espace ( ' ' , ASCII 0x20) et chaque mot doit être séparé par une barre oblique ( / , ASCII 0x2F).

Table de code Morse:

alt text http://soffr.miximages.com/code-golf/morse.gif

Cas de test:

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

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

Le compte de code comprend les entrées / sorties (c’est-à-dire le programme complet).

C (131 caractères)

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

J’ai ajouté quelques caractères supplémentaires en combinant la logique des boucles while et for en une boucle for , et en déplaçant la déclaration de la variable c dans la définition main tant que paramètre d’entrée. Cette dernière technique que j’ai empruntée à la réponse du joueur à un autre défi .


Pour ceux qui essaient de vérifier le programme avec GCC ou avec des éditeurs ASCII uniquement, vous pouvez avoir besoin de la version suivante, légèrement plus longue:

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

Cette version est plus longue de 17 caractères (pesant à peu près 148), en raison des modifications suivantes:

  • +4: getchar() et putchar() place du getch() non portable getch() et du putch()
  • +6: codes d'échappement pour deux des caractères au lieu de caractères non-ASCII
  • +1: 32 au lieu de 0 pour le caractère d'espace
  • +6: ajout de " c<0?1: " pour supprimer les erreurs de caractères inférieures à ASCII 32 (à savoir, de '\n' ). Vous obtiendrez toujours des ordures de n'importe lequel de ces fichiers!

Cela devrait rendre le code complètement portable. Comstackr avec:

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

Le -std=c89 est facultatif. Le caractère -funsigned-char est nécessaire, cependant, ou vous obtiendrez des erreurs pour la virgule et l'arrêt complet.


135 caractères

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

À mon avis, cette dernière version est beaucoup plus attrayante visuellement. Et non, ce n'est pas portable, et il n'est plus protégé contre les entrées hors limites. Il a aussi une mauvaise interface utilisateur, en saisissant des caractères par caractères et en les convertissant en code Morse et sans condition de sortie (vous devez appuyer sur Ctrl + Pause ). Mais le code portable et robuste avec une belle interface utilisateur n’était pas obligatoire.

Une explication succincte du code suit:

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

Chaque caractère de la longue chaîne du code contient le code Morse codé pour un caractère de texte. Chaque bit du caractère encodé représente un tiret ou un point. Un représente un tiret et un zéro représente un point. Le bit le moins significatif représente le premier tiret ou point du code Morse. Un dernier bit de "garde" détermine la longueur du code. C'est-à-dire que le bit le plus élevé dans chaque caractère codé représente la fin du code et n'est pas imprimé. Sans ce bit de garde, les caractères avec des points à la fin ne pouvaient pas être imprimés correctement.

Par exemple, la lettre "L" est " .-.. " en code Morse. Pour représenter cela en binary, nous avons besoin d'un 0, d'un 1 et de deux autres, en commençant par le moins significatif: 0010. Collez un autre 1 pour un bit de garde, et nous avons notre code Morse codé: 10010 18. Ajoutez le décalage +34 pour obtenir 52, qui est la valeur ASCII du caractère '4'. Ainsi, le tableau de caractères codé a un "4" comme 33ème caractère (index 32).

Cette technique est similaire à celle utilisée pour encoder les caractères des solutions ACoolie , strager (2) , Miles , pingw33n , Alec et Andrea , mais elle est légèrement plus simple, ne nécessitant qu'une opération par bit (décalage / division) plutôt que deux (décalage / diviser et décrémenter).

MODIFIER:
En parcourant le rest des implémentations, je constate qu'Alec et Anon ont mis au point ce schéma de codage - en utilisant le bit de garde - avant moi. La solution d'Anon est particulièrement intéressante, car elle utilise la fonction bin de Python et "0b" préfixe "0b" et le bit de garde avec [3:] , plutôt que de boucler, déplacer et déplacer, comme Alec et moi.

En bonus, cette version gère également le tiret ( -....- ), la barre oblique ( -..-. ), Les deux-points ( ---... ), le point-virgule ( -.-.-. ), -.-.-. égal à ( -...- ), et au signe ( .--.-. ). Tant que les caractères de 8 bits sont autorisés, ces caractères ne nécessitent aucun octet de code supplémentaire à prendre en charge. Aucun autre personnage ne peut être pris en charge avec cette version sans append de longueur au code (sauf s'il existe des codes Morse pour des signes plus / moins grands).

Parce que je trouve les anciennes implémentations toujours intéressantes et que le texte contient des mises en garde applicables à cette version, j'ai laissé le contenu précédent de ce post ci-dessous.


Ok, probablement, l'interface utilisateur peut sucer, non? Donc, en empruntant à strager , j'ai remplacé gets() , qui fournit une entrée de ligne mise en mémoire tampon avec écho, avec getch() , qui fournit une entrée de caractère non tamponnée et non sécurisée. Cela signifie que chaque caractère que vous tapez est immédiatement traduit en code morse sur l'écran. Peut-être que c'est cool. Il ne fonctionne plus avec stdin ou un argument de ligne de commande, mais il est vraiment petit.

J'ai conservé l'ancien code ci-dessous pour référence. Voici le nouveau.

Nouveau code, avec vérification des bornes, 171 caractères:

 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 interrompt la boucle et quitte le programme.

Nouveau code, sans vérification des bornes, 159 caractères:

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

Ci-dessous, l'ancien code 196/177, avec quelques explications:

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

Ceci est basé sur la réponse Python d'Andrea , utilisant la même technique pour générer le code morse que dans cette réponse. Mais au lieu de stocker les caractères encodables les uns après les autres et de trouver leurs index, j'ai stocké les index les uns après les autres et les ai recherchés par caractère (comme dans ma réponse précédente ). Cela évite les longs intervalles vers la fin qui ont causé des problèmes aux développeurs précédents.

Comme précédemment , j'ai utilisé un caractère supérieur à 127. La conversion en ASCII ajoute 3 caractères. Le premier caractère de la chaîne longue doit être remplacé par \x9C . Le décalage est nécessaire cette fois-ci, sinon un grand nombre de caractères est inférieur à 32 et doit être représenté avec des codes d'échappement.

Comme précédemment, le traitement d'un argument de ligne de commande au lieu de stdin ajoute 2 caractères et l'utilisation d'un caractère d'espace réel entre les codes ajoute 1 caractère.

Par contre, certaines des autres routines ne traitent pas des entrées en dehors de la plage acceptée de [, .0-9 \? A-Za-z]. Si une telle manipulation était supprimée de cette routine, 19 caractères pourraient être supprimés, ce qui ramènerait le total à 177 caractères. Mais si cela est fait et qu'une entrée non valide est transmise à ce programme, il peut tomber en panne et graver.

Le code dans ce cas pourrait être:

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

Utiliser une police de code Morse ?

 Console.Write(params[0]); 

Perl, 170 caractères (avec un peu d’aide de golfeur accompli mauke ). Enveloppé pour plus de clarté; toutes les nouvelles lignes sont amovibles.

 $_=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 

Explication:

  1. Extraire le dictionnaire morse Chaque symbole est défini par deux caractères, qui peuvent être soit des points, soit des tirets, soit une référence à la valeur d’un autre caractère défini. E et T contiennent des caractères fictifs pour éviter de désynchroniser le décodeur; nous les retirerons plus tard.
  2. Lire et formater l’entrée. "Hello world" devient "HELLO / WORLD"
  3. L’étape suivante dépend de la distinction entre les dictionnaires d’entrée et de sortie. Transformez les points en entrée en caractères inutilisés (barre verticale, | )
  4. Remplacez tout caractère dans l’entrée qui apparaît dans le dictionnaire morse par sa valeur dans le dictionnaire, jusqu’à ce qu’il n’y ait aucun remplacement.
  5. Retirez le caractère factice mentionné à l’étape 1.
  6. Imprimez la sortie.

Dans la version finale, le dictionnaire est optimisé pour l’efficacité de l’exécution:

  • Tous les caractères à un symbole (E et T) et les caractères à deux symboles (A, I, M et N) sont définis directement et décodés en une seule fois.
  • Tous les caractères à trois symboles sont définis en termes de caractère à deux symboles et de symbole littéral, en deux passages.
  • Tous les caractères à quatre symboles sont définis en termes de deux caractères à deux symboles, décodés en deux passages avec trois remplacements.
  • Les caractères à cinq et six symboles (chiffres et ponctuation) sont décodés en trois passages, avec respectivement quatre ou cinq remplacements.

Comme le code golfé ne remplace qu’un caractère par boucle (pour enregistrer un caractère de code!), Le nombre de boucles est limité à cinq fois la longueur de l’entrée (trois fois la longueur de l’entrée si seuls les caractères alphabétiques sont utilisés). Mais en ajoutant un g à l’opération s/// , le nombre de boucles est limité à trois (deux si seulement l’alphabet est utilisé).

Exemple de transformation:

 Hello 123 HELLO / 1 2 3 II .] AI AI M- / AO UM SM .... . .-.. .-.. --- / .-M- .A-- I.-- .... . .-.. .-.. --- / .---- ..--- ...-- 

Compréhension de la liste Python, une seule ligne de 159 caractères

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

Utilise le regroupement de données similaire à l’implémentation C de P Daddy , mais ne stocke pas les bits dans l’ordre inverse et utilise bin() pour extraire les données plutôt que l’arithmétique. Notez également que les espaces sont détectés en utilisant l’inégalité; il considère que chaque caractère “moins que la virgule” est un espace.

Python for boucle, 205 caractères incluant les nouvelles lignes

 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, 

Je me promenais avec un codage compact pour les symboles, mais je ne vois pas si je vais mieux que les arbres implicites déjà utilisés, alors je présente le codage ici au cas où quelqu’un d’autre pourrait l’utiliser.

Considérez la chaîne:

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

qui contient toutes les séquences nécessaires en tant que sous-chaînes. Nous pourrions coder les symboles par offset et par longueur comme ceci:

  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 --..--..-.-.-..--...----.....-----.--/ 

avec l’espace (c’est-à-dire la limite du mot) commençant et finissant sur le caractère final (le «/»). N’hésitez pas à l’utiliser, si vous voyez le bon chemin.

Bien entendu, la plupart des symboles plus courts ont plusieurs codages possibles.


P Daddy a trouvé une version plus courte de cette astuce (et je peux maintenant voir au moins une partie de la redondance ici) et a réalisé une belle implémentation. Alec a réalisé une implémentation de python avec la première version (buggy et incomplète). Hobbs a fait une version perl compacte que je ne comprends pas du tout.

J, 124 130 134 caractères

 '.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.>E20+193ACD'{~0>.45-~aitoupper 

J bat C! Impressionnant!

Usage:

  '.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.>E20+193ACD'{~0>.45-~aitoupper 'Hello World' .... . .-.. .-.. --- / .-- --- .-. .-.. -.. '.- /'{~;2,~&.>(]`(<&3:)@.(a:=])"0)}.&,&#:&.>E20+193ACD'{~0>.45-~aitoupper 'Hello, Stackoverflow.' .... . .-.. .-.. --- .-.-.- / ... - .- -.-. -.- --- ...- . .-. ..-. .-.. --- .-- --..-- 

Python 3 One Liner: 172 caractères

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

(Encodage de la table de traduction en points de code Unicode. Fonctionne bien et s’affiche très bien dans mon test sur mon ordinateur Windows Vista.)

Édité pour réduire à 184 caractères en supprimant des espaces et des crochets inutiles (en faisant la liste des comps gén exps).

Éditez à nouveau: Plus d’espaces supprimés que je ne savais même pas étaient possibles avant de voir d’autres réponses ici – donc jusqu’à 176.

Éditez à nouveau jusqu’à 172 (woo woo!) En utilisant «.join au lieu de» .join et en séparant les espaces. (duh!)

Caractères C # 266

La solution de 131 caractères C traduite en C # donne 266 caractères:

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

qui est plus lisible comme:

 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 caractères – NO FUNNY CHARS 🙂

newline à la fin de l’entrée n’est pas supporté, donc utilisez quelque chose comme ça

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

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

Les lettres sont un cas particulier et converties en minuscules et ordonnées dans leurs positions binarys.
Tout le rest est fait par une table de traduction

Python

Une solution incomplète, mais peut-être que quelqu’un peut en tirer une solution complète. Ne gère pas les chiffres ni la ponctuation, mais ne pèse que 154 caractères.

 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 caractères)

Une autre solution basée sur les arbres.

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

Peut-être des erreurs dans l’arborescence car wikipedia semble avoir tort ou peut-être que j’ai mal compris quelque chose.

F #, 256 caractères

 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:ssortingng)=s.ToUpper()|>Seq.fold(fun s c->s+match c with |' '->"/ "|','->"--..-- "|'.'->".-.-.- "|_->D(int c-48))"" 

Par exemple

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

les rendements

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

Je pense que ma technique peut être unique jusqu’à présent. L’idée est la suivante:

  • il y a une gamme de caractères ascii qui couvre la plupart de ce que nous voulons (0..Z)
  • il y a seulement 43 caractères dans cette gamme
  • ainsi nous pouvons encoder un bit (tiret ou point) plus un “caractère suivant” dans une gamme de 86 caractères
  • la plage ascii (32-117) est tout ‘imprimable’ et peut servir de plage de 86 caractères
  • de sorte que le littéral de chaîne encode une table le long de ces lignes

Il y a un peu plus, mais c’est l’essentiel. La virgule, le point et l’espace ne sont pas compris dans la plage 0..Z, ils sont donc traités spécialement par la correspondance. Certains caractères ‘inutilisés’ dans l’intervalle 0..Z (comme ‘;’) sont utilisés dans le tableau comme suffixes d’autres traductions de morse qui ne sont pas elles-mêmes des ‘lettres’ morse.

Voici ma consortingbution en tant qu’application console dans VB.Net

 Module MorseCodeConverter Dim M() As Ssortingng = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."} 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 

J'ai laissé l'espace blanc pour le rendre lisible. Totaux 1100 caractères. Il lira l'entrée de la ligne de commande, une ligne à la fois, et renverra la sortie correspondante au stream de sortie. La version compressée est ci-dessous, avec seulement 632 caractères.

 Module Q Dim M() As Ssortingng={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----."} 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 caractères)

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

Cela prend l’entrée de stdin. La saisie de la ligne de commande ajoute 2 caractères. Au lieu de:

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

vous obtenez:

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

J’utilise la page de codes de Windows-1252 pour les caractères supérieurs à 127, et je ne sais pas comment ils vont apparaître dans les navigateurs d’autres personnes. Je remarque qu’au moins dans mon navigateur (Google Chrome), deux des caractères (entre “@” et “i”) n’apparaissent pas. Si vous copiez hors du navigateur et collez-le dans un éditeur de texte, cependant, ils apparaissent, mais sous forme de petites boîtes.

Il peut être converti en ASCII uniquement, mais cela ajoute 24 caractères, ce qui augmente le nombre de caractères à 257. Pour ce faire, je décale d’abord chaque caractère de la chaîne de -64, réduisant ainsi le nombre de caractères supérieurs à 127. Puis Je substitue \x XX caractères à échapper si nécessaire. Cela change ceci:

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

pour ça:

 ...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(... 

Voici une version plus joliment formatée et commentée du code:

 /* writes `n` characters from internal ssortingng 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 ssortingng 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 * ssortingng. 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 comstacks and runs */ char *p, c, s[99]; /* p is a pointer within the input ssortingng */ /* c saves from having to do `*p` all the time */ /* s is the buffer for the input ssortingng */ 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 ssortingng */ } /* end main */ 

Cela bat tout ici sauf pour quelques implémentations Python. Je continue à penser que ça ne peut pas être plus court, mais je trouve un moyen de me débarrasser de quelques autres personnages. Si quelqu’un peut trouver plus de place à l’amélioration, faites le moi savoir.

MODIFIER:

J’ai remarqué que, bien que cette routine rejette tous les caractères non valides au-dessus de ASCII 44 (ne contenant qu’un espace vide pour chacun), elle ne vérifie pas les caractères non valides sous cette valeur. Pour vérifier cela, 5 caractères sont ajoutés à la longueur totale, en changeant ceci:

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

pour ça:

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

REBOL (118 caractères)

Une mise en œuvre d’environ 10 ans

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

Cité à partir de: http://www.rebol.com/oneliners.html

(pas de chiffres et les mots sont simplement séparés par des espaces doubles: / …)

Python (210 caractères)

Ceci est une solution complète basée sur celle d’ Alec

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

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(Ssortingng.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 m = new Dictionary() { {'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 ssortingng” 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 

Explication:

  • 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 ssortingng”.
  • The remainder of the data ssortingng stores the starting position and length of subssortingngs of the reference ssortingng 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 sortingcks 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)) 

Limites:

  • dmckee’s ssortingng 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 ssortingng 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 

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 = Ssortingng program :: Ssortingng 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 -> Ssortingng 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  #include  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);}}