| Bytes | Lang | Time | Link |
|---|---|---|---|
| 206 | C++20 pedantic | 250909T075339Z | Toby Spe |
| 193 | AWK | 250908T155623Z | xrs |
| 192 | x8616 machine code | 190106T152229Z | 640KB |
| 283 | C clang | 190202T215742Z | a stone |
| 165 | IBM PC DOS 8088 machine language | 190211T043354Z | Deadcode |
| 179 | JavaScript | 190204T000153Z | Yair Ran |
| 228 | C++ | 190202T085300Z | Deadcode |
| nan | PHP | 190201T234146Z | 640KB |
| 212 | PHP | 190131T141544Z | Titus |
| 183 | PowerShell | 190127T094131Z | mazzy |
| 225 | PowerShell | 190127T000836Z | GMills |
| 106 | Japt | 190104T201310Z | Shaggy |
| 313 | TSQL | 190110T124422Z | t-clause |
| 189 | JavaScript ES6 | 190104T230442Z | Rick Hit |
| 166 | Perl 6 | 190104T222827Z | Jo King |
| 218 | C# Visual C# Interactive Compiler | 190104T203923Z | Gymhgy |
| 057 | sfk | 190105T201050Z | Οurous |
| 218 | Clean | 190105T195357Z | Οurous |
| 193 | Red | 190105T084644Z | Galen Iv |
| 095 | 05AB1E | 190104T204021Z | Kevin Cr |
| 099 | Charcoal | 190105T112330Z | Neil |
| 191 | Python 3 | 190104T230945Z | Neil A. |
| 077 | Jelly | 190104T205725Z | Jonathan |
C++20 (pedantic), 206 bytes
Requires an ASCII-compatible character encoding.
[](auto s,auto&o){for(auto
c:s){o<<c;c&=31;auto&t="LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu";for(auto
d:t)if(!(c-=d<96))o<<d;o<<' ';}}
How it works
#include <ostream>
#include <string_view>
void transform(std::string_view str, std::ostream& out)
{
for (char c: str) {
out << c;
c &= 31; // SPC = 0, A,a = 1, B,b = 2, etc.
const char prowords[] =
"LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIke"
"OvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu";
for (char d: prowords) {
if (d < 96) { // upper case
--c;
}
if (c == 0) {
// we're in the target pro-word
out << d;
}
}
out << ' ';
}
};
Demo program
constexpr auto transform =
[](auto s,auto&o){for(auto
c:s){o<<c;c&=31;auto&t="LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu";for(auto
d:t)if(!(c-=d<96))o<<d;o<<' ';}};
#include <iostream>
#include <iterator>
#include <string>
int main()
{
for (std::string s; std::getline(std::cin, s); ) {
transform(s, std::cout);
std::cout << '\n';
}
}
AWK, 193 bytes
{for(;i++<NF;)if(match("IndiAlfABravOscaRomeOQuebeCharliEchODeltAGolFoxtroTangOHoteLimAJulietTKilOZulUniforMikENovembeRPapASierrAVictoRWhiskeYankeEXraY",toupper($i)".[a-z]+[A-Z]",m))print m[0]}
Used a trick from this to shave a few bytes.
x86-16 machine code, IBM PC DOS, 192 bytes
be80 00ad 8ac8 ac51 24df 8ad0 2c40 3c1b 7321 8af0 b024 b18b 9090 bf37 01f2 aefe
ce75 fab4 02cd 218b d7b4 09cd 21b2 20b4 02cd 2159 e2d0 c324 6c66 6124 7261 766f
2468 6172 6c69 6524 656c 7461 2463 686f 246f 7874 726f 7424 6f6c 6624 6f74 656c
246e 6469 6124 756c 6965 7474 2469 6c6f 2469 6d61 2469 6b65 246f 7665 6d62 6572
2473 6361 7224 6170 6124 7565 6265 6324 6f6d 656f 2469 6572 7261 2461 6e67 6f24
6e69 666f 726d 2469 6374 6f72 2468 6973 6b65 7924 7261 7924 616e 6b65 6524 756c
7524
MOV SI, 80H ; point SI to DOS PSP
LODSW ; load arg length into AL, advance SI to 82H
MOV CL, AL ; set up loop counter
SEARCH:
LODSB ; load next char from DS:SI into AL, advance SI
PUSH CX ; save outer loop position
AND AL, 0DFH ; uppercase the input letter
MOV DL, AL ; save for output
SUB AL, 'A'-1 ; convert letter to one-based index (A=1, Z=26, etc)
CMP AL, 27 ; if greater than 26, not a valid char
JNC NOTFOUND ; if not, move to next
MOV DH, AL ; DH is loop counter
MOV AL, '$' ; search for string delimiter
MOV CL, LNATO ; repeat search through length of word data
MOV DI, OFFSET NATO ; re-point SCASB to beginning of word data
SCANLOOP:
REPNZ SCASB ; search until delimiter in AL is found ES:DI, advance DI
DEC DH ; delimiter found, decrement counter
JNZ SCANLOOP ; if counter reached 0, index has been found
MOV AH, 02H ; display first char
INT 21H
MOV DX, DI ; put found string memory location to DX for display
MOV AH, 09H ; display string function
INT 21H
MOV DL, ' ' ; display a space between words
MOV AH, 02H
INT 21H
NOTFOUND:
POP CX ; restore outer loop counter
LOOP SEARCH ; move to next char in input
RET
NATO DB '$lfa$ravo$harlie$elta$cho$oxtrot$olf$otel$ndia$'
DB 'uliett$ilo$ima$ike$ovember$scar$apa$uebec$omeo$'
DB 'ierra$ango$niform$ictor$hiskey$ray$ankee$ulu$'
LNATO EQU $-NATO
Test output:
A>NATO abc aaa
Alfa Bravo Charlie Alfa Alfa Alfa
A>NATO abc DefG1HIJ
Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett
A>NATO Alfa Bravo!
Alfa Lima Foxtrot Alfa Bravo Romeo Alfa Victor Oscar
C (clang), 309 283 bytes
-26 bytes thanks to @ceilingcat
*k[]={"lfa","ravo","harlie","elta","cho","oxtrot","olf","otel","ndia","uliett","ilo","ima","ike","ovember","scar","apa","uebec","omeo","ierra","ango","niform","ictor","hiskey","ray","ankee","ulu"};i;main(z,v)char**v;{for(;z=toupper(v[1][i]);i++)z>64&z<92&&printf("%c%s ",z,k[z-65]);}
IBM PC DOS 8088 machine language, 165 bytes
This is directly based on gwaugh's answer, but I shaved off 26 bytes by omitting the $ delimiters from the "NATO" word table and an extra 1 byte by not skipping the first character of the command-line parameter string (which will always be either / or and thus will be ignored by the program anyway). The program ended up being exactly the same length to be able to process the table in this format (in which the words are delimited only by uppercase characters, which serve the double purpose of also being the second letter of each word), or 2 bytes longer if the output capitalization is kept the same as before. The table is 26 bytes smaller.
In the following program dump, concatenation by : is used to show each sequence of consecutive bytes corresponding to an instruction:
0000 BE:80:00 AC 91 AC 24:DF 8A:D0 2C:40 3C:1A 77:21 ······$···,@<·w!
0010 8A:F0 B4:02 CD:21 56 BE:34:01 AC A8:20 75:FB FE: ·····!V·4··· u··
0020 :CE 75:F7 8A:D0 CD:21 AC A8:20 75:F7 B2:20 CD:21 ·u····!·· u·· ·!
0030 5E E2:D2 C3 4C 66 61 52 61 76 6F 48 61 72 6C 69 ^···LfaRavoHarli
0040 65 45 6C 74 61 43 68 6F 4F 78 74 72 6F 74 4F 6C eEltaChoOxtrotOl
0050 66 4F 74 65 6C 4E 64 69 61 55 6C 69 65 74 74 49 fOtelNdiaUliettI
0060 6C 6F 49 6D 61 49 6B 65 4F 76 65 6D 62 65 72 53 loImaIkeOvemberS
0070 63 61 72 41 70 61 55 65 62 65 63 4F 6D 65 6F 49 carApaUebecOmeoI
0080 65 72 72 61 41 6E 67 6F 4E 69 66 6F 72 6D 49 63 erraAngoNiformIc
0090 74 6F 72 48 69 73 6B 65 79 52 61 79 41 6E 6B 65 torHiskeyRayAnke
00A0 65 55 6C 75 40 eUlu@
Download the DOS NATO.COM executable:
With uncorrected capitalization (165 bytes)
With clean capitalization (167 bytes)
Bonus version that capitalizes the first letter of each word the same as the input (167 bytes)
Unassembled:
.MODEL TINY ; .COM program, maximum addressing space 65536 bytes
.CODE
ORG 100h
start:
MOV SI, 80h ; Point SI to DOS PSP (Program Segment Prefix).
LODSB ; Load command-line parameter (input string) length
; into AL; assume AX=0 before this, which is true
; in most versions of DOS; advance SI to first char
; of parameter, which is either '/' or ' '.
XCHG CX, AX ; Set up loop counter with length of input string.
search:
LODSB ; Load next character from [SI] into AL; advance SI.
AND AL, NOT ('A' XOR 'a') ; Make this character uppercase.
MOV DL, AL ; Save character for output. Move this before the
; AND instruction to capitalize the first letter of
; each word identically to how it is in the input.
SUB AL, 'A'-1 ; convert letter to one-based index (A=1, Z=26, etc)
CMP AL, 'Z'-'A'+1 ; Is this an alphabetical character?
JA notFound ; If not, move to next character.
MOV DH, AL ; Set up DH as our word-finding loop counter.
MOV AH, 02h ; AH=02h, INT 21h: Write character to STDOUT
INT 21h ; Display first character of this NATO word.
PUSH SI ; Save our current position in the input string.
MOV SI, OFFSET table ; Point LODSB to beginning of word data.
scanLoop: ; Find the word in the table corresponding to our
; current character.
LODSB ; Load next character from [SI] into AL; advance SI.
TEST AL, 'A' XOR 'a' ; Is this character uppercase?
JNZ scanLoop ; If not, move to next character.
DEC DH ; Delimiter (uppercase) found; decrement counter.
JNZ scanLoop ; Keep looping until counter reaches 0.
OR AL, 'A' XOR 'a' ; Make this character lowercase. This is not
; required by the challenge's specification, and
; this instruction can be removed.
wordLoop:
MOV DL, AL ; Display next character from NATO word.
INT 21h ; (We still have AH=02h from before.)
LODSB
TEST AL, 'A' XOR 'a' ; Is this character lowercase?
JNZ wordLoop ; If so, continue the loop.
MOV DL, ' ' ; Display a space between words.
INT 21h ; (We still have AH=02h from before.)
POP SI ; Restore our current position in the input string.
notFound:
LOOP search ; Move to next character in input string.
RET
table DB 'LfaRavoHarlieEltaChoOxtrotOlfOtelNdia'
DB 'UliettIloImaIkeOvemberScarApaUebecOmeo'
DB 'IerraAngoNiformIctorHiskeyRayAnkeeUlu'
DB '@' ; Terminate the list to make sure that uninitialized
; memory doesn't cause a problem.
END start
Sample input:
>NATO The quick brown fox jumped over the lazy dog.
>NATO Jackdaws love my big sphinx of quartz.
Output (165 byte version):
TAngo hOtel eCho qUebec uNiform iNdia cHarlie kIlo bRavo rOmeo oScar wHiskey nOvember fOxtrot oScar xRay jUliett uNiform mIke pApa eCho dElta oScar vIctor eCho rOmeo tAngo hOtel eCho lIma aLfa zUlu yAnkee dElta oScar gOlf
JUliett aLfa cHarlie kIlo dElta aLfa wHiskey sIerra lIma oScar vIctor eCho mIke yAnkee bRavo iNdia gOlf sIerra pApa hOtel iNdia nOvember xRay oScar fOxtrot qUebec uNiform aLfa rOmeo tAngo zUlu
Clean-capitalization version (167 bytes):
Tango Hotel Echo Quebec Uniform India Charlie Kilo Bravo Romeo Oscar Whiskey November Foxtrot Oscar Xray Juliett Uniform Mike Papa Echo Delta Oscar Victor Echo Romeo Tango Hotel Echo Lima Alfa Zulu Yankee Delta Oscar Golf
Juliett Alfa Charlie Kilo Delta Alfa Whiskey Sierra Lima Oscar Victor Echo Mike Yankee Bravo India Golf Sierra Papa Hotel India November Xray Oscar Foxtrot Quebec Uniform Alfa Romeo Tango Zulu
Clean-capitalization version with same capitalization as input (167 bytes):
Tango hotel echo quebec uniform india charlie kilo bravo romeo oscar whiskey november foxtrot oscar xray juliett uniform mike papa echo delta oscar victor echo romeo tango hotel echo lima alfa zulu yankee delta oscar golf
Juliett alfa charlie kilo delta alfa whiskey sierra lima oscar victor echo mike yankee bravo india golf sierra papa hotel india november xray oscar foxtrot quebec uniform alfa romeo tango zulu
JavaScript, 179 bytes
s=>s.match(/\w/g).map(c=>c+'LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu'.match(/.[a-z]+/g)[parseInt(c,36)-10])
C++, 229 228 bytes
[](auto s){for(;auto t=*s?"LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu":0;s++)if(int c=*s&31){for(cout<<*s;*t>96||--c;t++);for(;cout<<*t,*++t>96;);cout<<' ';}}
Ungolfed:
[](const char *s)
{
const char *table = "LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu";
for (; *s; s++)
{
char c = *s & 0x1F;
if (c != 0)
{
cout << *s;
const char *w = table;
while (*w >= 'a' || --c)
w++;
do
cout << *w;
while (*++w >= 'a');
cout << ' ';
}
}
}
Output:
TAngo hOtel eCho qUebec uNiform iNdia cHarlie kIlo bRavo rOmeo oScar wHiskey nOvember fOxtrot oScar xRay jUliett uNiform mIke pApa eCho dElta oScar vIctor eCho rOmeo tAngo hOtel eCho lIma aLfa zUlu yAnkee dElta oScar gOlf
JUliett aLfa cHarlie kIlo dElta aLfa wHiskey sIerra lIma oScar vIctor eCho mIke yAnkee bRavo iNdia gOlf sIerra pApa hOtel iNdia nOvember xRay oScar fOxtrot qUebec uNiform aLfa rOmeo tAngo zUlu
Clean-capitalization version (234 bytes):
[](auto s){for(;auto t=*s?"LfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu":0;s++)if(int c=*s&31){for(cout<<*s;*t>96||--c;t++);for(;putchar(*t|32),*++t>96;);cout<<' ';}}
Output:
Tango hotel echo quebec uniform india charlie kilo bravo romeo oscar whiskey november foxtrot oscar xray juliett uniform mike papa echo delta oscar victor echo romeo tango hotel echo lima alfa zulu yankee delta oscar golf
Juliett alfa charlie kilo delta alfa whiskey sierra lima oscar victor echo mike yankee bravo india golf sierra papa hotel india november xray oscar foxtrot quebec uniform alfa romeo tango zulu
PHP, 209 205 206 bytes
while($l=$argv[1][$x++])echo$l!=' '?$l.preg_split('/([A-Z][a-z]*)/',ALfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu,0,3)[31&ord($l)].' ':'';
Output:
"Hello World" => "HOtel eCho lIma lIma oScar WHiskey oScar rOmeo lIma dElta"
Or 195 bytes, with spaces not fully removed:
while($l=$argv[1][$x++])echo$l,preg_split('/([A-Z][a-z]*)/',ALfaRavoHarlieEltaChoOxtrotOlfOtelNdiaUliettIloImaIkeOvemberScarApaUebecOmeoIerraAngoNiformIctorHiskeyRayAnkeeUlu,0,3)[31&ord($l)].' ';
Output:
"Hello World" => "HOtel eCho lIma lIma oScar WHiskey oScar rOmeo lIma dElta"
PHP, 212 bytes
while($c=ord($argn[$i++]))echo[_,Alpha,Bravo,Charlie,Delta,"Echo",Foxtrot,Golf,Hotel,India,Juliett,Kilo,Lima,Mike,November,Oscar,Papa,Quebec,Romeo,Sierra,Tango,Uniform,Victor,Whiskey,Xray,Yankee,Zulu][$c&31]," ";
Run as pipe with -nR or try it online.
Yields warnings in PHP 7.2; put array elements in quotes to fix.
Will print an underscore for spaces.
PowerShell, 187 183 bytes
$args|% t*y|%{'AlfaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJuliettKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu'-csplit'(?=[A-Z])'-like"$_*"}
Test script:
$f = {
$args|% t*y|%{'AlfaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJuliettKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu'-csplit'(?=[A-Z])'-like"$_*"}
}
@(
,('Hello World', 'Hotel', 'Echo', 'Lima', 'Lima', 'Oscar', 'Whiskey', 'Oscar', 'Romeo', 'Lima', 'Delta')
) | % {
$s,$expected = $_
$result = &$f $s
"$result"-eq"$expected"
"$result"
}
Output:
True
Hotel Echo Lima Lima Oscar Whiskey Oscar Romeo Lima Delta
PowerShell, 228 225 bytes
-3 bytes thanks to @mazzy
"$args".ToLower()-replace' '|% T*y|%{$a+=$_+((-split"lfa ravo harlie elta cho oxtrot olf otel ndia uliett ilo ima ike ovember scar apa uebec omeo ierra ango niform ictor hiskey ray ankee ulu")[('a'..'z').IndexOf($_)])+' '};$a
This is quite possibly the ugliest piece of code I have ever written. In addition, this can certainly get a lot shorter. In my defense, I'm still recovering from final exams.
Japt, 108 106 bytes
¸®¬Ë+u cg`ovem¼rws¯r°pawue¼cÙ o±ØÇ¯fmØtØkeyÙ°nkeewªuwlfaæ1ÃÉr¦e³ltawÖoxÉwolfÙ*lÙAawªieâ-¹µ±ke`qw
The backticks contains the compressed string:
ovemberwscarwapawuebecwomeowierrawangowniformwictorwhiskeywraywankeewuluwlfawravowharlieweltawchowoxtrotwolfwotelwndiawuliettwilowimawike
TSQL, 313 bytes
Golfed:
DECLARE @ varchar(max)='Hello World'
DECLARE @x INT=len(@)WHILE @x>0SELECT @=stuff(@,@x,1,substring(@,@x,1)+choose(ascii(substring(@,@x,1))%32,'lfa','eta','harlie','elta','cho','oxtrot','olf','otel','ndia','uliett','ilo','ima','ike','ovember','scar','apa','uebec','omeo','ierra','ango','niform','ictor','hiskey','ray','ankee','ulu')+';'),@x-=1PRINT @
Ungolfed:
DECLARE @ varchar(max)='Hello World'
DECLARE @x INT=len(@)
WHILE @x>0
SELECT @=stuff(@,@x,1,substring(@,@x,1)+choose(ascii(substring(@,@x,1))%32,
'lfa','eta','harlie','elta','cho','oxtrot','olf','otel','ndia','uliett','ilo',
'ima','ike','ovember','scar','apa','uebec','omeo','ierra','ango','niform',
'ictor','hiskey','ray','ankee','ulu')+';'),
@x-=1
PRINT @
Output ends with semicolon
JavaScript (ES6), 181 189 bytes
s=>s.match(/\w/g).map(c=>'IndiAlfABravOscaRomeOQuebeCharliEchODeltAGolFoxtroTangOHoteLimAJulietTKilOZulUniforMikENovembeRPapASierrAVictoRWhiskeYankeEXraY'.match(c.toUpperCase()+'.*?[A-Z]'))
Since output case doesn't matter, we can save bytes by running words together:
... GolFoxtroTangO ...
Perl 6, 176 170 166 bytes
*.comb>>.&{$_~:128[q`>$RbD[Orlo~Q1nX,OVq8x9'6%h'1.I$83ua7 vsD=s-{W}{>iQ:Js37py)hNN,i{Pt\~#f4<>`.ords].base(35).split('J')[.ord%32]}.words
Outputs in uppercases with the first letter in the original case. Compresses the string, which only saves 6 bytes over the simpler plain text:
*.comb>>.&{$_~ <lfa ravo harlie elta cho oxtrot olf otel ndia uliett ilo ima ike ovember scar apa uebec omeo ierra ango niform ictor hiskey ray ankee ulu>[.ord%32-1]if ' 'ne$_}
Explanation:
*.comb>>.&{ } # Map each letter to
$_~ # The letter plus
<...>[.ord%32] # The letter indexed into the list of words
.words # And remove the extra spaces
C# (Visual C# Interactive Compiler), 218 bytes
n=>n.ToUpper().Select(x=>"AlfaBravoCharlieDeltaEchoFoxtrotGolfHotelIndiaJuliettKiloLimaMikeNovemberOscarPapaQuebecRomeoSierraTangoUniformVictorWhiskeyXrayYankeeZulu".SkipWhile(k=>x!=k).TakeWhile((k,l)=>l<1|k>96&k<123))
Alternate version using Split(), 194 bytes
n=>n.ToUpper().Select(x=>x>64?x+"lfa,ravo,harlie,elta,cho,oxtrot,olf,otel,ndia,uliett,ilo,ima,ike,ovember,scar,apa,uebec,omeo,ierra,ango,niform,ictor,hiskey,ray,ankee,ulu".Split(',')[x%65]:x+"")
sfk, 78 59 57 bytes
+filt
+spell -nato
+xed _ph_f_ _et_ett_ _-__ "*: [keep]""
Just use the right tool.
Output is the phonetics separated by one or more spaces.
Clean, 218 bytes
import StdEnv
$s=[takeWhile((<=)c)(dropWhile((<)c)['ZuluYankeeXrayWhiskeyVictorUniformTangoSierraRomeoQuebecPapaOscarNovemberMikeLimaKiloJuliettIndiaHotelGolfFoxtrotEchoDeltaCharlieBravoAlfa'])\\c<-map toUpper s|c>' ']
Red, 210 193 bytes
func[s][foreach c trim/all s[prin c print pick[:lfa:ravo:harlie:elta:cho:oxtrot:olf:otel:ndia:uliett:ilo:ima:ike:ovember:scar:apa:uebec:omeo:ierra:ango:niform:ictor:hiskey:ray:ankee:ulu]c% 32]]
Explanation:
foreach iterates over the string after all whitespaces are removed by trim/all. prin prints the character (no newline). print prints a symbol, picked from the list of get-word!s (symbols) using the character mapped to the range 1..26 as an index.
05AB1E, 102 96 95 bytes
álSA”AlfaІvo¼¯¤œ®È¨›trotŠˆƒ‹Š™ÈŸtt Kilo´àma—……ÍЗŽêpa¼°«Äoµ†Çâgo¸šÉµ Whiskey Xrayµ‹nkeeâ¸lu”#‡
Output is a list of Titlecased NATO words.
Explanation:
á # Only leave the letters of the (implicit) input
l # Convert it to lowercase
S # Split it to a list of characters
A # Push the alphabet
”...” # Push all the NATO words in titlecase and space-delimited
# # Split the string by spaces
‡ # Transliterate; map all letters in the lowercase input with this
# list at the same indices (and output the resulting list implicitly)
See this 05AB1E tip of mine (section How to use the dictionary?) to understand why ”AlfaІvo¼¯¤œ®È¨›trotŠˆƒ‹Š™ÈŸtt Kilo´àma—……ÍЗŽêpa¼°«Äoµ†Çâgo¸šÉµ Whiskey Xrayµ‹nkeeâ¸lu” is "Alfa Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliett Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu". Credit of this compressed dictionary string goes to @ErikTheGolfer in this comment (with an added t for Juliett instead of Juliet).
Charcoal, 99 bytes
EΦ↥S№αι⁺ι§⪪”&⌊%w⁸D⦃σν:…ⅈ$|@H¦χT⸿]ECrΣM^¿←←&⁵↘⁼s(JF8X´▷⧴⎚P0V÷AWχπ¶⌈≧\"dJ^ZU{M≔⁴|<¶⁹B⊞⊟1LPH⪪∨Y3`”j⌕αι
Try it online! Link is to verbose version of code. Outputs in proper case. Explanation:
S Input string
↥ Uppercased
Φ Filtered where
α Predefined uppercase alphabet
№ Contains
ι Current character
E Mapped over characters
ι Current character
⁺ Concatenated with
”...” Compressed string
⪪ Split on
j Literal string `j`
§ Indexed by
⌕ Index of
ι Current character
α In uppercase alphabet
Implicitly print each word on its own line
Python 3, 250 191 bytes
-47 bytes thanks to @Jo King, -2 more thanks to @Jonathan Allen
It goes through all non-space characters of the input, and for each of them it selects the relevant phrase for the letter, which can be reduced a bit because the first letter of each phrase is the character itself. Splits a string instead of storing the phrases as an array to save bytes from the unnecessary 's and ,s.
lambda s:[c+"lfa ravo harlie elta cho oxtrot olf otel ndia uliett ilo ima ike ovember scar apa uebec omeo ierra ango niform ictor hiskey ray ankee ulu".split()[ord(c)%32-1]for c in s if' '<c]
Original solution
lambda s:[c+['lfa','ravo','harlie','elta','cho','oxtrot','olf','otel','ndia','uliett','ilo','ima','ike','ovember','scar','apa','uebec','omeo','ierra','ango','niform','ictor','hiskey','ray','ankee','ulu'][ord(c)-65]for c in s.replace(" ", "").upper()]
Jelly, 80 77 bytes
ḟ⁶O%32ị“¡µQỤ(cɠṘwlṁ;Ɗœ<NẸ½ṗN¬ṙẋxḶb¤*O~ƃ¹.ß8Ḋ¡tJ|Ḷ<İİḂ^1eȷjċbY9TYƭ¹Ẉ¥¤K0¹f»Ḳ¤
Try it online! (The footer formats the list by joining with spaces to avoid implicit smashing print when run as a full program)