Input: A single word as a string (matches [a-zA-Z]+). If the input doesn't follow these guidelines, print "Error" (but no error should be thrown)

Output: The NATO pronunciation of the word. Print out a space separated list of the NATO word that matches each letter of the input word. Trailing white space is acceptable.

Your source code must contain each ASCII character from 32 (space) to 126 (tilde) in that order, excluding numbers and letters. You may have anything you like mingled in between the required characters, but the required characters must be there and in order. (If ABC were the required characters, YA8iBC3 or C6ABn#C would be valid, but A7CRT or 8mdB9AC would not be).

Standard loopholes and built-ins for generating the NATO pronunciation are not allowed.

The NATO pronunciation is as follows: Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu.

The required symbols (in order) are as follows: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

Test cases: (The quotation marks won't be part of input, but are included to show whitespace)

"a"            => Alpha
"Z"            => Zulu
"twig"         => Tango Whiskey India Golf
"PPCG"         => Papa Papa Charlie Golf
"camelCase"    => Charlie Alpha Mike Echo Lima Charlie Alpha Sierra Echo
"Quebec"       => Quebec Uniform Echo Bravo Echo Charlie
""             => Error
" "            => Error
"()"           => Error
"twig "        => Error
" PPCG"        => Error
"one+two"      => Error
"Queen bee"    => Error

This is a , so the shortest code in your favorite language wins!

  • 9
    \$\begingroup\$ +1 for the basic challenge idea but -1 for the (in my opinion) odd and unnecessary restrictions. \$\endgroup\$
    – Alex A.
    Dec 28, 2015 at 18:30
  • 1
    \$\begingroup\$ Wtf those strange restrictions?.. What's the use of making !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ required? \$\endgroup\$
    – nicael
    Dec 28, 2015 at 18:49
  • 1
    \$\begingroup\$ @AlexA. The restrictions are the core of the challenge. The rest of the challenge is simply the framework to present the restriction. \$\endgroup\$ Dec 28, 2015 at 19:32
  • \$\begingroup\$ Let's say wed have met the requirement while writing the source code, can we use those characters afterwards? \$\endgroup\$
    – TanMath
    Dec 31, 2015 at 17:14
  • \$\begingroup\$ Yes. You can use the symbols as many times as you'd like. \$\endgroup\$ Dec 31, 2015 at 21:26

8 Answers 8


JavaScript (ES6), 268

An anonymous function

i=>[...i].every(c=>(c=parseInt(c,36))>9?o+="AlphaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJulietKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu".match(/[A-Z][^A-Z]+/g)[c-10]+' ':0,o='',!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~")?o:'Error'

Ruby, 343 bytes

puts gets.chop.chars.map!{|c|"AlphaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJulietKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu"[/#{c.upcase}[a-z]+/]||$$%0&0}*' 'rescue(puts"Error")#*+,-./:;<=>?@[\]^_`{|}~

Tried incorporating as many of the required characters as possible, but after a while it was shorter to just put them in a comment at the end. For readability, here's the non-comment part with the long string taken out:

puts gets.chop.chars.map!{|c|"AlphaBravo..."[/#{c.upcase}[a-z]+/]||$$%0&0}*' 'rescue(puts"Error")

That's a space and all the characters !"#$%&'() in the right order without comments

  • \$\begingroup\$ Can get it to 197 these days, using the normal codegolf rules about functions. x.chars.map{"AlphaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJulietKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu"[/#{_1.upcase}[a-z]+/]||1/0}*' 'rescue"Error" \$\endgroup\$
    – DrQuarius
    May 8, 2023 at 1:22
  • \$\begingroup\$ Attempt this online! \$\endgroup\$
    – DrQuarius
    May 8, 2023 at 1:22
  • \$\begingroup\$ Oops, 227. Forgot about the silly requirement. \$\endgroup\$
    – DrQuarius
    May 8, 2023 at 1:42

05AB1E, 151 150 146 145 143 135 bytes

!áмg_ilA”¤±Ð†vo¼¯¤œ®È¨›trotŠˆƒ‹Š™ÈŸt Kilo´àma—……ÍЗŽêpa¼°«Äoµ†Çâgo¸šÉµ Whiskey Xrayµ‹nkeeâ¸lu”#ð«‡ë”‰ë”q"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

-8 bytes implicitly thanks to @ErikTheGolfer's comment here for a better compressed string (only difference is Alpha vs Alfa).

Try it online or verify all test cases.


!              # Take the factorial of the (implicit) input
               # (This will leave the input-string unchanged if it isn't an integer)
 áм            # Remove all letters
   g_i         # If the length of the remainder is 0:
      l        #  Make the (implicit) input lowercase
       A       #  Push the lowercase alphabet
       ”¤±Ð†vo¼¯¤œ®È¨›trotŠˆƒ‹Š™ÈŸt Kilo´àma—……ÍЗŽêpa¼°«Äoµ†Çâgo¸šÉµ Whiskey Xrayµ‹nkeeâ¸lu”
               #  Push string "Alpha Bravo Charlie ... Yankee Xray Zulu"
        #      #  Split the string by spaces:
               #   ["Alpha","Bravo","Charlie",...,"Yankee","Xray","Zulu"]
         ð«    #  Append each with a space:
               #   ["Alpha ","Bravo ","Charlie ",...,"Yankee ","Xray ","Zulu "]
       ‡       #  Transliterate; map all letters in the lowercase input with this
               #  list at the same indices (and output the result implicitly)
     ë         # Else:
      ”‰ë”     #  Push the dictionary word "Error"
          q    # Stop the program (and output the "Error" at the top of the stack implicitly)
              "# Push the string "#$%&'()*+,-./:;<=>?@[\]^_`{|}~",
               # which is a no-op since the program has already stopped

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why ”¤±Ð†vo¼¯¤œ®È¨›trotŠˆƒ‹Š™ÈŸt Kilo´àma—……ÍЗŽêpa¼°«Äoµ†Çâgo¸šÉµ Whiskey Xrayµ‹nkeeâ¸lu” is "Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu" and ”‰ë” is "Error".


CJam, 173 bytes

qeu:M'[,65>:L- !{M'Af-L"{;ege& \@IQ#5~wUNxuznY_E+TLsBTC9\$8
]%9b    Y9&G~|Yedz9?7pLD&&6PNg[vXY4D}Q"127b26b'`f+'`/.+f=S*}"Error"?e#()*+,-./:;<=>?@[\]^_`{|}~

Contains lots of unprintable characters. Try it out here.


PHP, 268 bytes

Same byte count as the JavaScript answer. :) I couldn't find a byte-saving way around the "penalty" of adding the special char string as is:

for(;$c=ucfirst($argv[1][$i++]);"!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~")preg_match("/{$c}[a-z]+/",AlphaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJulietKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu,$m)?$o.="$m[0] ":die(Error);echo$o;

Takes an input from command line, like:

$ php tango.php Word


    preg_match("/{$c}[a-z]+/",AlphaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJulietKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu,$m) ?
        $o.="$m[0] " :

x86 machine code, IBM PC DOS, 274 bytes

a080 0032 e4fe c8be 8100 03f0 8bc8 8bd8 b805 008e c0fd ac24 dfbf 0800 51b1 a4fc
f2ae 5975 064f 57e2 eceb 07ba af00 52bb 0100 8cc0 8ed8 b409 8bcb 5acd 21ba b400
cd21 e2f6 b44c cd21 416c 7068 6124 4272 6176 6f24 4368 6172 6c69 6524 4465 6c74
6124 4563 686f 2446 6f78 7472 6f74 2447 6f6c 6624 486f 7465 6c24 496e 6469 6124
4a75 6c69 6574 244b 696c 6f24 4c69 6d61 244d 696b 6524 4e6f 7665 6d62 6572 244f
7363 6172 2450 6170 6124 5175 6562 6563 2452 6f6d 656f 2453 6965 7272 6124 5461
6e67 6f24 556e 6966 6f72 6d24 5669 6374 6f72 2457 6869 736b 6579 2458 7261 7924
5961 6e6b 6565 245a 756c 7524 2122 2345 7272 6f72 2024 2526 2728 292a 2b2c 2d2e
2f3a 3b3c 3d3e 3f40 5b5c 5d5e 5f60 7b7c 7d7e 


NATO    DB  'Alpha$Bravo$Charlie$Delta$Echo$Foxtrot$Golf$Hotel$India$'
        DB  'Juliet$Kilo$Lima$Mike$November$Oscar$Papa$Quebec$Romeo$'
        DB  'Sierra$Tango$Uniform$Victor$Whiskey$Xray$Yankee$Zulu$'
        DB  '!"#'           ; required string part 1
ERRSTR  DB  'Error'         ; Error string
SEPSTR  DB  ' $'             ; word separator string  
        DB  '%&',"'()*+,-./:;<=>?@[\]^_`{|}~" ; required string part 2
    MOV  AL, DS:[80H]       ; DS:80H is length of input string from command line
    XOR  AH, AH             ; clear AH
    DEC  AL                 ; command line arg length includes preceeding space
    MOV  SI, 81H            ; look in DS:82H-1 for start of string
    ADD  SI, AX             ; start at end of string
    MOV  CX, AX             ; search length of input string
    MOV  BX, AX             ; BL is length of input to search
    MOV  AX, @DATA          ; Initialize ES to CODE segment
    MOV  ES, AX             ; align ES pointer (leave DS pointing to PSP)
    STD                     ; set dir flag (search backwards)
    LODSB                   ; load next char from DS:SI into AL, advance SI 
    AND  AL, 0DFH           ; uppercase the input letter
    MOV  DI, OFFSET NATO    ; re-point SCASB to beginning of word data
    PUSH CX                 ; save outer loop position
    MOV  CL, LNATO          ; CL = length of NATO word data
    CLD                     ; clear dir flag (search forward)
    REPNE SCASB             ; search until key in AL is found ES:DI, advance DI
    POP  CX                 ; restore outer loop counter
    JNZ  SHORT ERROR        ; if REPNE ends without ZF, no value was found  
    DEC  DI                 ; un-advance DI to start of found string
    PUSH DI                 ; save position for later output
    MOV  DX, OFFSET ERRSTR  ; error string
    PUSH DX                 ; push to top of stack
    MOV  BX, 1              ; only output this one below
    MOV  AX, ES             ; get data segment from ES
    MOV  DS, AX             ; point DS for DOS API string output
    MOV  AH, 09H            ; display string function
    MOV  CX, BX             ; loop for number of input letters
    POP  DX                 ; get pointer to next word from stack
    INT  21H
    MOV  DX, OFFSET SEPSTR  ; display a space between words
    INT  21H
    MOV  AH, 4CH            ; exit to DOS
    INT  21H

Reads input from command line, displays output to console.

Implementation notes: In order to prevent any otherwise valid words from being displayed before the Error string, the searching and screen output are separate. The input string is searched end to beginning since the stack (LIFO) is used to hold the output words (otherwise they'd be displayed in reverse).


Tango Whiskey India Golf
Papa Papa Charlie Golf
A>SYMLET camelCase
Charlie Alpha Mike Echo Lima Charlie Alpha Sierra Echo
Quebec Uniform Echo Bravo Echo Charlie
A>SYMLET "twig "
A>SYMLET one+two
A>SYMLET Queen bee
  • \$\begingroup\$ This is very impressive, nice job. \$\endgroup\$
    – Riker
    Jan 4, 2019 at 20:10

Japt, 188 bytes

The compressed string is littered with unprintables, so I've replaced each with a ¿. Try it online!

V=Um@`Alp¿B¿voC¿r¦eDeltaE®oFoxÉ¿GolfHÇUI¿iaJªietKiloL¿aMikeNovem¼rOs¯rPapaQue¼cRo´oSi¿¿TangoUnif¿mVÅ¡rW¿skeyX¿yY¿keeZªu`fXu +"[a-z]+" +S};!Uf"[ !#$%&'()*+,-./:;<=>?@[\\]^_`\{|}~]" ?V:`Er¿r
                                                                                                                                     ^    ^  ^   ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^

The top line is the actual code; the bottom line points out each of the required characters. I was lucky to find a way to put every one of them to good use, especially the backslash, which would have been needed there even if it was not required.

I could save four bytes by using JS's atob to compress the string, instead of Japt's built-in Oc, but the transpiler inserts an extra parenthesis due to this bug.

V=Um@     }; // Set variable V to: map each character X in U to:
`...`f       //  Take the long string, decompress it, and match:
Xu +"[a-z]+" //   the uppercase version of X, followed by multiple lowercase letters.
+S           //  Take the resulting match and add a space.
             // All this results with "Alpha Bravo Charlie" for an input of "Abc", or
             // "Alpha Bravo null" for something like "Ab!".
 Uf"..."     // Match any of the characters in this string in the input.
!        ?   // If the result is null (none were matched):
V            //  output V.
:"Error      // Otherwise, output "Error".

Python 279 276 bytes

It would have been much shorter than the odd requirement.

EDIT: I just learned that s.split(' ')==s.split()

l="Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu".split()
for i in x: a+=l[ord(i)-97]+' '
print a

I commented out the requirement. I used ord() to find the index position of the letter in l.

Try it here!

  • \$\begingroup\$ It doesn't matter for this challenge, but note that ''.split(' ') is [''] but ''.split() is []. \$\endgroup\$
    – Alexia
    Jan 9, 2016 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.