Traduire le code Morse en fonction de la durée du son

36

Objectif

Le code Morse est souvent représenté sous forme de son. Si un flux de bits indique si le son est activé ou non, traduisez-le en lettres, en chiffres et en espaces.

International Morse Code

Détails

  • Le flux de bits est analysé en fonction de la longueur des bits ON / OFF répétés.
    • 1 bit ON est un point
    • 3 ON bits sont un tiret
    • 1 bit OFF délimite les points et les tirets
    • 3 bits OFF délimite les caractères
    • 7 bits OFF délimitent les mots (espace)
  • L'entrée peut être une chaîne ou un tableau. Seuls deux caractères / valeurs uniques de votre choix sont autorisés dans l'entrée. (par exemple, 0/1, vrai / faux, virgule / espace)
  • La sortie renvoie une chaîne ou est imprimée sur la sortie standard.

Exemple

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

Hypothèses

  • Le flux commence et finit toujours avec un bit ON.
  • Il n'y a pas d'espaces de début ou de fin.
  • L'entrée est toujours valide.
  • Toutes les lettres (insensibles à la casse) et les chiffres sont pris en charge.

Cas de test

101010100010001011101010001011101010001110111011100000001011101110001110111011100010111010001011101010001110101
HELLO WORLD

10100000001011100011101110000000101110000000101011101000101000101010001010101
I AM A FISH

1010111011101110001110111011101110111000101110111011101110001110111010101
2017

101010001110111011100010101
SOS

Notation

C'est du code golf. Le code de nombre d'octets le plus bas à cette heure-là la semaine prochaine l'emporte.

Hand-E-Food
la source
La sortie peut-elle avoir des espaces de fin?
Brian J

Réponses:

9

APL (Dyalog) , 65 62 60 57 octets

-3 grâce à ngn.

Fonction de préfixe tacite.

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

Essayez-le en ligne! Header, f←et Footer servent uniquement à appeler la fonction depuis Input tout en conservant le nombre d'octets de TIO. Dans une session APL normale (correspondant au champ d'entrée de TIO), cela ne serait pas nécessaire .

⎕CY'dfns'c op y l' espace de travail dfns (bibliothèque)

(... ) appliquer cette fonction tacite:
'1+|(00)+'⎕S 1 PCRE S earch 1-runs et même longueur 0 points fixes et les longueurs de matches retour
6| le reste de la division lorsqu'il est divisé par 6
⊃∘'/. -'¨ pour chaque longueur de correspondance, choisir le caractère correspondant de cette chaîne
'/|[-.]+'⎕S'&'∘ PCRE S les barres obliques de et tableau de bord / point -runs et renvoyer ceux
morse traduits du code Morse en texte normal

Adam
la source
5
Wow, je ne savais jamais que Dyalog possédait un code morse intégré.
Zacharý
@ Zacharý Il y a beaucoup, beaucoup de tâches intégrées dans les dfns.
Erik l'Outgolfer
@ Zacharý Toujours vérifier dfns !
Adám
Vous vous connectez à une ancienne version.
Erik the Outgolfer
Une fonction BF ...> _ <, wow.
Zacharý
8

Python 2 , 142 135 octets

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

Essayez-le en ligne!

Explication:

Divise la chaîne en lettres 000( 0signifie donc espace)

Remplace chacun 111par 3et se transforme en base 16.

Ensuite, chaque nombre est modifié par 57, ce qui donne une plage de 0..54, qui est l'index du caractère actuel.


Version précédente convertie en base 3:

Python 2 , 273 252 247 octets

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

Essayez-le en ligne!

Version précédente convertie en binaire:

Python 2 , 282 261 256 octets

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

Essayez-le en ligne!

TFeld
la source
5

Ruby , 123 octets

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

Essayez-le en ligne!

Fractionner la chaîne d'entrée sur la limite de caractères. Utilisez 3 ou 4 bits OFF pour que les espaces soient convertis en chaînes vides. Prenez la valeur de base 2 de chaque caractère et ramenez-la dans une plage raisonnable (moins de 60 valeurs possibles) en utilisant modulo sur 3 divisions successives.

GB
la source
Très bien fait.
Rétablir Monica iamnotmaynard
2
Je suis sûr que cela fonctionne pour tous les cas, mais si vous supprimez 0?de l’expression rationnelle, cela fonctionne toujours pour les quatre cas de test.
Jordanie
4

Python , 175 168 octets

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

Commencez par convertir la chaîne en liste de chaînes 0 (tiret) / 1 (point), ajoutez un préfixe 1(pour éviter les zéros non significatifs et pour gérer les espaces), puis convertissez-la en binaire.

Étant donné que chaque code n'a pas plus de 5 caractères, le résultat est compris entre 0 et 63 et peut être répertorié dans une chaîne.

Colera Su
la source
1
J'ai obtenu indépendamment la même solution, mais 169 octets:lambda s:''.join("_ TEMNAIOGKDWRUS__QZYCXBJP_L_FVH09_8___7_______61_______2___3_45"[int('1'+filter(int,l).replace('2','0'),2)]for l in s.replace('111','2').split('000'))
Alex Varga
@AlexVarga Belle utilisation de Python 2 filter!
Colera dim
3

Gelée , 67 à 62 octets

ṣ0L€«2ḅ2“>.&" þ/7;=¥çı¿¢×ÆФ怌©¦Çß÷µ¬£®Ñ½ðȷñ‘iịØB;⁶¤
œṣ0ẋ3¤Ç€

Essayez-le en ligne!

Erik le golfeur
la source
Attendez, la numérotation des liens se termine?
Zacharý
@ Zacharý Oui, les liens de ligne ont des index modulaires.
Erik the Outgolfer
3

Visual Basic .NET (.NET Core) , 252 octets

-7 octets grâce à @recursive

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

Une fonction qui prend une chaîne de 1s et 0s et retourne une chaîne. (En fait, seul le 0pour le OFFest une exigence absolue. OFFOn suppose que tout ne l' est pas ON).

Le littéral de chaîne correspond à la configuration du code Morse en tant que segment binaire sous forme de tableau. VB.NET vous permet d'indexer des chaînes en tant que tableaux de caractères. le\ division est un entier, prenant le sous-tas de gauche pour 1ou le sous-tas de droite pour 111.

j'ai utilisé ! comme un blanc pour quand il n'y a pas de valeur dans cet endroit tas. Il est seulement nécessaire de remplir correctement les index.

VB.NET vous permet de revenir en affectant une valeur au nom de la fonction (dans ce cas, A). Je viens de faire des concaténations de chaînes ( &) de manière itérative pour construire la chaîne de sortie. La toute première fois que je dois utiliser &parce que l’utilisation +laisse un caractère nul de tête, mais je peux l’utiliser à tout autre moment +, ce qui se comporte de la même manière que &pour les chaînes.

Essayez-le en ligne!

Brian J
la source
1
Vous pouvez enregistrer 7 octets à l'aide de l' "!ETIANMSURWDKGOHVF!L!PJBXCYZQ!!5473!!8290!!!!!16"indexation, puis l'indexation M(c-c\48*22), puis 4 autres en ne l'utilisant même pas M, mais en utilisant simplement le littéral de chaîne en ligne.
récursive
@recursive Je comprends le tour de 4 octets, merci pour l'aide! J'ai du mal à comprendre comment vous modifiez l'indice. Si je remplace le littéral chaîne, puis l'utilise M(c-c\48*22), j'obtiens un index hors limites pour le cas 2017. Je pense que VB fera la division et la multiplication à la même priorité; est-ce qu'il me manque une parenthèse?
Brian J
Vous avez raison sur la priorité. c\48*22sera soit 0ou 22. C'est une manière de soustraire conditionnellement 22 à c, de Mraccourcir en "pliant" la fin de la chaîne. Si cela ne fonctionne pas pour vous, vous pouvez toujours supprimer les parens de A &=(" ")2 autres octets. :)
récursif
Et puis vous pouvez changer &=pour +=et enlever deux autres espaces.
récursif
@recursive Oh, duh! trop de parens supplémentaires. Le problème avec le passage à plus est alors que j'ai un caractère null au début de ma chaîne. Peut-être que ce n'est pas un gros problème, cependant.
Brian J
3

JavaScript (ES6), 170 131 octets

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


Comment ça marche:

Si vous modifiez les points en 0 et les tirets en 1 et en préfixant 1, vous obtenez des nombres binaires qui, convertis en décimales, vous donnent:

  1. Lettres: 2 - 18, 20 et 22 - 29.
    Celles-ci peuvent être converties en lettres correctes en indexant en ' ETIANMSURWDKGOHVF L PJBXCYZQ'.
  2. Nombres: 32, 33, 35, 39, 47, 48, 56, 60, 62 et 63.
    Si nous prenons ces nombres, module 11, nous obtenons les nombres 0 - 8 et 10, qui peuvent être convertis en nombres corrects avec indexation dans'473168290 5' .

Le programme se divise en caractères, puis convertit chaque caractère en points et en tirets, qui sont convertis en sortie appropriée en fonction des règles ci-dessus.


Cas de test:

Rick Hitchcock
la source
3

Python 2 , 127 octets

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

Essayez-le en ligne!

Tirer parti de la solution de TFeld en supprimant replace , en travaillant en base 10, au prix d’un xor au niveau des bits et d’une chaîne de référence plus longue.

Joe
la source
2

PHP, 321 284 bytes

Saved 37 bytes thanks to @ovs

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

Previous version (321 bytes)

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

Try it online!

Ungolfed version :

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

Java (OpenJDK 8), 370 bytes

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

Try it online!

  • 3 bytes saved thanks to @Jeutnarg.
Olivier Grégoire
la source
1
can shave off a few by using Long.toString(x[i],2) instead of Integer.toString(x[i],2)
Jeutnarg
2

GNU sed, 261 + 1 = 262 bytes

+1 byte for -r flag.

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

Try it online!

Explanation

This is a very basic lookup table solution.

The first three lines transform the input so dashes are _s and dots are 1s. First, 000s are replaced with ;, so characters are separated by ; and words by ;;0. Then 111s are replaced by _ and all remaining 0s are discarded, leaving 1s for dots.

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

The next line appends the lookup table. It takes the form cmcmcm... where c is a character and m is the sequence of _s and 1s representing it. i is substituted for 1 in the table for disambiguation. Since regular expressions in sed are always greedy, the table is sorted from longest to shortest code (so e.g. 1_ matches A1_ instead of i1____).

s/$/;:51111141111_3111__211___i1____6_11117__1118___119____10_____H1111V111_F11_1L1_11P1__1J1___B_111X_11_C_1_1Y_1__Z__11Q__1_S111U11_R1_1W1__D_11K_1_N__1G__1O___I11A1_M__E1T_/

Next, in a loop, each sequence of _s and 1s (and the subsequent ;) is replaced by the corresponding character:

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

Finally, cleanup: is are replaced with 1s, remaining ;s are spaces, and the lookup table is deleted:

y/i/1/
s/;/ /g
s/:.*//g
Jordan
la source
1

Jelly, 67 bytes

ŒrḌṣ7ṣ€3ṣ€€1’H_4F€€ḅ3i@€€“ṗƙ⁶}zyȮẓŀȯ¦CFæ¢+ı(¥5ç1®¬ȷ4MÑÆ£Ç)×DGL‘ịØBK

Try it online!

HyperNeutrino
la source
1

JavaScript (ES6), 104 102 101 99 bytes

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

Test cases

How?

Because converting from binary to decimal costs bytes, we use a hash function which works directly on binary blocks interpreted in base 10.

Example

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

--> The 21st character in the lookup table is 'L' (0-indexed).
Arnauld
la source
I like this one-step approach very much. How big a search did you perform to fit these 37 outputs into a perfect hash of size 50 with a short enough function?
jayprich
@jayprich This was brute-forced. It was almost 1 year ago, though, so I don't remember exactly how. :) Chances are that I tried all n*p%m0%m1 for 1p<10000, 1<m0<10000 and 1<m1<100.
Arnauld
1

Retina, 144 138 130 103 bytes

T`d`@#
^|@@@

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

Try it online! Link includes test cases. Explanation:

T`d`@#

Change the binary digits to other characters because 0 and 1 are valid outputs.

^|@@@
 

Insert a space before every character and two spaces between words.

 @?#
E

Assume that all characters are Es.

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

Translate all letters assuming that they will be followed by a dot. For instance, if we have an E, and we see a second dot (we consumed the first when we inserted the E) then it translates to an I. For letters that can only be legally followed by a dash, they are translated with that assumption, and then the dash is consumed by the next stage. Other letters are deleted (keeping L costs a byte).

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

If it transpires that they were in fact followed by a dash, then fix up the mistranslations. This also consumes the dash when it was assumed by the previous stage. Both translations are repeated until all of the dots and dashes are consumed.

Neil
la source
0

Perl 5, 241 + 1 (-p) = 242 bytes

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

Try it online!

Xcali
la source
0

PHP, 181+1 bytes

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

Run as pipe with -nR or try it online.

Titus
la source
0

ES6, 268 bytes

Uses ASCII encoding after mapping from a base36 representation of the morse to an index position. Not my best golf day, but it only took around 15 mins.

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

Easier to read (kinda):

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

binarymax
la source
0

Wolfram Language (Mathematica), 288 bytes

Thought about reading in the data as binary from a file but that gets hard to explain. Base 36 seemed like a good compromise way to store the data efficiently lexically.

Takes a string of 0's and 1's as input. Does a series of replacements, starting with the runs of 7 zeros, then the runs of 3, then the longest binary letters down to the shortest. Order of replacement is important.

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

Try it online!

Kelly Lowder
la source
Wait, Mathematica doesn't have a morse code built-in?
Zacharý
Not yet! I checked.
Kelly Lowder
0

Perl 5, 195 bytes

194 bytes code + 1 for -p.

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

I couldn't get this working with just a standard packed binary string, I had to escape the higher-byte chars otherwise I'd be on 171, if anyone knows what I've missed, or why it's breaking that'd be great!

Try it online!

Explanation

The binary string is a packed list of the numbers that relate to the morse characters (101011101 - 349 for F etc) and this is zipped with the ranges A..Z,0..9 and used as a lookup. The s/// expressions replace all runs of seven 0s with space and then all runs of digits, separated with three 0s or word boundaries \b, with their corresponding key from the %h hash.

Dom Hastings
la source