g | x | w | all
Bytes Lang Time Link
062JavaScript V8250731T104426Zuser3048
048ARM64 machine code250714T021445ZNate Eld
nanTuring Machine Code250714T222737ZErikDaPa
073Swift 6250710T180457ZmacOSist
032Japt250609T163353ZShaggy
nanCP1610 machine code250617T091851ZArnauld
033Opcode x64250617T102350Zl4m2
072Python 3250611T103332Zuser3048
063C gcc250611T083747Zuser3048
646VBA250610T182429Zmc-gwidd
058GNU sed e250610T162142ZToby Spe
nanCommodore 64 Assembler250608T195454ZJani Joe
02305AB1E250610T082203ZKevin Cr
104C64 Basic250609T155843ZOSI8
107Google Sheets250608T123334Zdoubleun
052Ruby pl250608T011347ZValue In
061Perl 5 F250608T211150ZXcali
032Vyxal 3250608T200159Zpacman25
067R250608T071632Zpajonk
093APL+WIN250608T150501ZGraham
024Jelly250608T173039ZJonathan
047Retina 0.8.2250607T234926ZNeil
062JavaScript Node.js250608T010034Zl4m2
029Charcoal250608T065330ZNeil
071JavaScript ES6250607T235700ZArnauld
163TinyAPL250607T235629ZRubenVer
158Google Sheets / Excel250607T233623Zz..

JavaScript (V8), 62 bytes

JavaScript anonymous function that performs the specified operation using string substitution and regular expressions. Should be engine-agnostic. Strings of appropriate length are identified by the regular expression based on the first matched character and subsequently replaced by the first character of the matched string. Minor golfing trick in the expression by adding a superfluous O to the last class so that NOVEMBER can be matched with the corresponding sub-expression.

s=>s.replace(/([BDHIORT]|[QSVY].|N?[CFJOUW]..)?..../g,t=>t[0])

Try it online!

ARM64 machine code, 48 bytes

Takes pointer to null-terminated input in x0, pointer to output buffer (which must be large enough) in x1, following standard AAPCS calling conventions for void nato(const char *in, char *out);.

Little-endian hex words:

58000143
38404402
38001422
d37ff844
9ac42065
8b45f800
7101385f
9a801400
35ffff22
d65f03c0
267b2000
074c5c0d

Assembly:

nato:
    ldr   x3, table
again:
    ldrb  w2, [x0], #4 // skip 4 bytes automatically
    strb  w2, [x1], #1
    lsl   x4, x2, #1 // 2 bits per table entry
    lslv  x5, x3, x4
    add   x0, x0, x5, lsr #62
    cmp   w2, #'N'
    cinc  x0, x0, eq
    cbnz  w2, again
    ret
table:
    .xword 0x074c5c0d267b2000

Approach is similar to x86 solution by l4m2 (but I thought of it mostly independently). We use a 2-bit lookup table in a register to find the length of the mnemonic minus 4. There is special code to handle N.

Comments:

Turing Machine Code, 34 / 121 rules

0 A * r 3
0 B * r 4
0 C * r 6
0 D * r 4
0 E * r 3
0 F * r 6
0 G * r 3
0 H * r 4
0 I * r 4
0 J * r 6
0 K * r 3
0 L * r 3
0 M * r 3
0 N * r 7
0 O * r 4
0 P * r 3
0 Q * r 5
0 R * r 4
0 S * r 5
0 T * r 4
0 U * r 6
0 V * r 5
0 W * r 6
0 X * r 3
0 Y * r 5
0 Z * r 3
0 _ * * halt
7 * _ r 6
6 * _ r 5
5 * _ r 4
4 * _ r 3
3 * _ r 2
2 * _ r 1
1 * _ r 0

Note: This program replaces unnecessary letters with spaces instead of removing them. Therefore, you will see spaces in between letters.

Try this online!

Second longer program:

0 A * r 3 ; # of letters to delete ahead ↓
0 B * r 4
0 C * r 6
0 D * r 4
0 E * r 3
0 F * r 6
0 G * r 3
0 H * r 4
0 I * r 4
0 J * r 6
0 K * r 3
0 L * r 3
0 M * r 3
0 N * r 7
0 O * r 4
0 P * r 3
0 Q * r 5
0 R * r 4
0 S * r 5
0 T * r 4
0 U * r 6
0 V * r 5
0 W * r 6
0 X * r 3
0 Y * r 5
0 Z * r 3
0 _ * l RW ; now to the deleting spaces part
7 * x r 6  ; deleting letters 
6 * x r 5
5 * x r 4
4 * x r 3
3 * x r 2
2 * x r 1
1 * x r 0
RW x _ l RW ; delete trailing spaces
RW * * r ML ; when reached letter, shift to the right
ML * * l ML 
ML x 0 l MV ; until reaching first x from the right, mark a 0
MV x x l MV ; now search for another letter ↓
MV A x r A
MV B x r B
MV C x r C
MV D x r D
MV E x r E
MV F x r F
MV G x r G
MV H x r H
MV I x r I
MV J x r J
MV K x r K
MV L x r L
MV M x r M
MV N x r N
MV O x r O
MV P x r P
MV Q x r Q
MV R x r R
MV S x r S
MV T x r T
MV U x r U
MV V x r V
MV W x r W
MV X x r X
MV Y x r Y
MV Z x r Z
MV _ _ r CL
A x x r A  ; replacing 0 with that letter ↓
A 0 A r ML
B x x r B
B 0 B r ML
C x x r C
C 0 C r ML
D x x r D
D 0 D r ML
E x x r E
E 0 E r ML
F x x r F
F 0 F r ML
G x x r G
G 0 G r ML
H x x r H
H 0 H r ML
I x x r I
I 0 I r ML
J x x r J
J 0 J r ML
K x x r K
K 0 K r ML
L x x r L
L 0 L r ML
M x x r M
M 0 M r ML
N x x r N
N 0 N r ML
O x x r O
O 0 O r ML
P x x r P
P 0 P r ML
Q x x r Q
Q 0 Q r ML
R x x r R
R 0 R r ML
S x x r S
S 0 S r ML
T x x r T
T 0 T r ML
U x x r U
U 0 U r ML
V x x r V
V 0 V r ML
W x x r W
W 0 W r ML
X x x r X
X 0 X r ML
Y x x r Y
Y 0 Y r ML
Z x x r Z
Z 0 Z r ML
CL x _ r CL ; now just clear unnecessary prefix
CL 0 _ r CL
CL * * * halt

Note: This one removes the extra spaces instead, but however it is longer. Probably need some optimizations.

Try this online!

Desmos, 210 bytes

Input is a list of codepoints.

L=I-64                                                  => convert into idx in the alphabet
S=[4,5,7,5,4,7,4,5,5,7,4,4,4,8,5,4,6,5,6,5,7,6,7,4,6,4] => length of the phonetic spelling of each letter
s=S[L][x]
G(L,x)=[G(L,x-1)-1,s][2-sign(G(L,x-1)-1)]               => create decreasing idx from each head letter
G(L,1)=s
H(L,x)=\left\{x=1,G(L,x-1)=1,0\right\}                  => mark idx of head letters
A=[L[x]H(L,x)forx=[1...L.count]]
f(I)=A[A>0]+64                                          => keep head letters and convert back to letters (as codepoints)

Try this online!

Swift 6, 73 bytes

{($0+"").replacing(/(?=(.))([BDHIORT]|[QSVY].|N?[CFJOUW]..)?..../){$0.1}}

Try it on SwiftFiddle!

A direct port of the Retina answer.

Japt, 32 bytes

Adaptation of Arnauld's solution.

©Î+ßUs`35c‹9Ÿt …nwbd¦`¸mn33 ¬gUc

Try it

©Î+ßUs`...`¸mn33 ¬gUc     :Implicit input of string U
©                         :Logical AND with
 Î                        :  First character of U
  +                       :  Append
   ß                      :    Recursive call with argument
    Us                    :      Slice U from index
      `...`               :        Compressed string "35cim9rat atnwbdli"
           ¸              :        Split on spaces
            m             :        Map
             n33          :          Convert from base 33
                 ¬        :        Join
                  g       :        Get character at 0-based index
                   Uc     :          Codepoint of first character of U

CP-1610 machine code, 34 DECLEs1=42.5 bytes

1. CP-1610 instructions are encoded with 10-bit values (0x000 to 0x3FF), known as DECLEs. Although the Intellivision is also able to work on 16-bit data, programs were really stored in 10-bit ROM back then.

A routine that takes the address of a NUL-terminated string in R3 and writes another NUL-terminated string at the address in R4.

Source code

                        ROMW  10              ; use 10-bit ROM
                        ORG   $4800           ; map our program at $4800
                
                  PRINT EQU   $1867           ; PRINT routine from the EXEC
                  BT    EQU   $200            ; BACKTAB address
                  OUT   EQU   $300            ; output address
                
                        ;; --------------------------------------------------------- ;;
                        ;;  main code                                                ;;
                        ;; --------------------------------------------------------- ;;
4800 001                SDBD                  ; set up an interrupt service routine
4801 2B8 068 048        MVII  #isr, R0        ; to do some minimal STIC initialization
4804 240 100            MVO   R0, $100
4806 040                SWAP  R0
4807 240 101            MVO   R0, $101
                
4809 002                EIS                   ; enable interrupts
                
480A 001                SDBD                  ; test #1
480B 2BB 02F 048        MVII  #test1, R3
480E 2BC 300            MVII  #OUT, R4
4810 004 148 076        CALL  nato
                
4813 2B9 300            MVII  #OUT, R1        ; print the result
4815 2BB 007            MVII  #7, R3
4817 2BC 200            MVII  #BT, R4
4819 004 118 067        CALL  PRINT
                
481C 001                SDBD                  ; test #2
481D 2BB 046 048        MVII  #test2, R3
4820 2BC 300            MVII  #OUT, R4
4822 004 148 076        CALL  nato
                
4825 2B9 300            MVII  #OUT, R1        ; print the result
4827 2BB 007            MVII  #7, R3
4829 2BC 214            MVII  #BT+20, R4
482B 004 118 067        CALL  PRINT
                
482E 017                DECR  R7              ; spin forever
                
482F 048 04F ...  test1 STRING  "HOTELECHOLIMALIMAOSCAR", 0
4846 051 055 ...  test2 STRING  "QUEBECUNIFORMECHOBRAVOECHOCHARLIE", 0
                
                        ;; --------------------------------------------------------- ;;
                        ;;  ISR                                                      ;;
                        ;; --------------------------------------------------------- ;;
                  isr   PROC
                
4868 240 020            MVO   R0, $0020       ; enable display
                
486A 1C0                CLRR  R0
486B 240 030            MVO   R0, $0030       ; no horizontal delay
486D 240 031            MVO   R0, $0031       ; no vertical delay
486F 240 032            MVO   R0, $0032       ; no border extension
4871 240 028            MVO   R0, $0028       ; black background
4873 240 02C            MVO   R0, $002C       ; black border
                
4875 0AF                JR    R5              ; return from ISR
                
                        ENDP
                
                        ;; --------------------------------------------------------- ;;
                        ;;  our routine ($4876 to $4897 -> 34 DECLEs)                ;;
                        ;; --------------------------------------------------------- ;;
                  nato  PROC
                
4876 299          @loop MVI@  R3, R1          ; R1 = input character
4877 261                MVO@  R1, R4          ; write it at R4
4878 089                TSTR  R1              ; stop if it's zero
4879 204 00F            BEQ   @done
                
487B 001                SDBD                  ; subtract 65 and add twice the address
487C 2F9 0D5 090        ADDI  #@len*2-65, R1  ; of the @len table (carry is cleared)
487F 071                RRC   R1              ; floor-divide by 2 by rotating
4880 289                MVI@  R1, R1          ; read the table
4881 201 002            BC    @adv            ; was the original value even? ...
                
4883 065                SLR   R1, 2           ; ... yes: right-shift by one nibble
4884 065                SLR   R1, 2
                
4885 3B9 00F      @adv  ANDI  #$F, R1         ; keep the least significant nibble
4887 0CB                ADDR  R1, R3          ; skip that many characters
4888 220 013            B     @loop           ; process the next character
                
488A 0AF          @done JR    R5              ; return
                
488B 045 075 ...  @len  DECLE $45, $75, $47, $45  ; A-H
488F 057 044 ...        DECLE $57, $44, $48, $54  ; I-P
4893 065 065 ...        DECLE $65, $65, $76, $74  ; Q-X
4897 064                DECLE $64                 ; Y-Z
                
                        ENDP

Output

output

Opcode (x64, Linux), 33 bytes

00000000: adad aa91 00c9 7409 48b8 d031 3570 98ed  ......t.H..15p..
00000010: 08c3 48d3 e83c 8774 e783 e003 4801 c6eb  ..H..<.t....H...
00000020: e0                                       .
fx:	lodsd
f:	lodsd
	stosb
	xchg ecx, eax
	add cl, cl
	jz .r-1  ; ret
	mov rax, 0xc308ed98703531d0
.r:	shr rax, cl
	cmp al, 0x87 ; It only appears at N
	jz fx
	and eax, 3
	add rsi, rax
	jmp f

Try it online!

Support both upper and lower case. Require few bytes after src readable.

Python 3, 72 bytes

Function f accepts an upper-case string and returns a lower-case string. This solution uses a slightly different method of compression from other solutions.

The word sizes are packed into an integer that is treated as a bit vector of 25×3 bits. This bit vector is then encoded in hexadecimal as the magic number 0x32430590834CA281800, which corresponds to the octal string 3110301310203231212014000. Note reverse order, which saves one byte in decoding despite the hexadecimal literal being two chars longer than otherwise (0x2108A2D308164304B, 17 digits, for the curious).

The correct length is then extracted from the string by shifting the appropriate amount (3×ordinal) and extracting the three least-significant bits using the modulo operator.

f=lambda s:s and s[0]+f(s[4+(0x32430590834CA281800>>ord(s[0])%25*3)%8:])

Try it online!

C (gcc), 67 63 bytes

Similar to many other approaches here, including Arnauld's. Input as a upper-case, widechar string with NUL terminator, output via stdout.

Length of the phonetic representation is encoded as a string and one character is extracted from the string based on the first character of input. Following a suggestion from @emanresu, the characters were changed from ASCII-encoding to raw bytes with values in the 4-8 range. The extracted character is then used to shift the string pointer to the right. The function then recurses, passing the pointer to the next invokation.

Golfy tricks include using && short circuiting for branching and recursion, rather than for. The return value of putchar() is used inside the array subscript (returns printed char on success). Obviously, widechar string used to shave a single byte off total solution.

f(int*s){*s&&f(s+"\4\4\4\8\5\4\6\5\6\5\7\6\7\4\6\4\5\7\5\4\7\4\5\5\7"[putchar(*s)%25]);}

Try it online!

For purposes of clarity, escape characters are used in the code snippet to represent the raw bytes, which would otherwise be non-graphical. Raw characters are used in the TIO source code.

VBA, 646 bytes

Public Function REVERSENATO(itext As String)

Dim clen As Long
Dim nato() As String
Dim ctext As String
Dim newstring As String
ReDim nato(26, 1)

For c = 1 To 26
nato(c, 0) = Sheets("Sheet1").Range("F" & c)
nato(c, 1) = Sheets("Sheet1").Range("G" & c)
Next c

ctext = itext
clen = Len(ctext)
Do Until clen = 0
    For test = 1 To 26
        If InStr(1, ctext, nato(test, 1)) = 1 Then
        ctext = Right(ctext, Len(ctext) - Len(nato(test, 1)))
        clen = Len(ctext)
        newstring = newstring & nato(test, 0)
        Exit For
        End If
    Next test
Loop
    
REVERSENATO = newstring
    
End Function

Not a good or small solution but I did it so that's something.

enter image description here

GNU sed -e, 58 bytes

s/(NOVE|[CFJUW]..|[QSVY].|[BDHIORT]|)..../\l&/g
s/[A-Z]//g

This produces lower-case output, which seems acceptable in such a decoder.

How it works: simple regex determines number of letters; \l downcases the first letter of each proword, then we remove all remaining capital letters.

Commodore 64 Assembler, 48 47 Bytes (6502/KickAssembler)

Explanation

Code uses very few special sizecoding tricks to reduce its size, it is pretty vanilla 6502 and quite compact by nature. Maybe only three things worth mentioning:

  1. Using an unintended opcode (that is, an opcode that isn't in the list of official opcodes of 6502 as provided by the manufacturer, but still works) LAX (Load to A and X) which loads the char's screencode to both A and X registers in one go. This negates the need for separate LDA (LoaD to Accumulator) and TAX (transfer A to X) commands, thus saving a byte.
  2. UPDATE: Instead of Absolute,Y addressing to point to the top of the screen, the aforementioned LAX uses Indirect Indexed addressing. In other words, lax $0400,y becomes lax ($0e),y, as memory addresses $0e-$0f happen to hold address $0400 after SYS. This saves another byte.
  3. Using the screencode of the first letter of the word as an index to the word lengths lookup table. Pretty common practice on old, slow systems, but maybe still worth mentioning as someone new to assembly may find this fascinating. It sure fascinated me when I learned about such usage for the first time. 😁 Screencodes for A-Z are $01-$1B, and table index is zero based, thus if we want the length for e.g. letter 'A', we just look up into table location table-1+'A'.

Code

* = $1000               // Run the program with SYS4096
        ldy #0          // Reset Y, which will be used as string index.
next:   lax ($0e),y     // Load char from string, indexed by Y, into A and X.
        cmp #$20        // Is it a whitespace char?
        beq done        // If yes, whole string is processed and we're done.
        adc #$40        // Convert screen code $01-$1b to PETSCII code $41-$5b...
        jsr $ffd2       // ...and call ROM routine to print the char on screen.
        tya             // Copy string index from Y to A...
        adc length-1,x  // ...and add length of the current word to it, using the
                        // charcode as the index to a lookup table with lengths.
        tay             // Copy updated string index back from A to Y.
        bcc next        // If we've not gone over 256 chars, continue.
done:   rts             // We're done - return to system.
length: .byte 4,5,7,5,4,7,4,5,5,7,4,4,4,8,5,4,6,5,6,5,7,6,7,4,6,4

05AB1E, 23 bytes

Δć©?•2úèæ…½D₅’wη•A®kè.$

I/O in lowercase.

Try it online or verify all test cases.

Explanation:

Δ                 # Loop until the result no longer changes,
                  # using the (implicit) input-string in the first iteration:
 ć                #  Extract the head of the current string
  ©               #  Store this in variable `®` (without popping)
   ?              #  Pop and output this letter
    •2úèæ…½D₅’wη• #  Push compressed integer 3464363446333743545465635
      A           #  Push the lowercase alphabet
       ®          #  Push letter `®`
        k         #  Get the index of this letter in the alphabet
         è        #  Use that to index into the compressed integer
                  #  (index 25 for 'z' will wrap around to the leading 3)
          .$      #  Remove that many leading characters from the remainder-string

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •2úèæ…½D₅’wη• is 3464363446333743545465635.

C64 Basic, 104 bytes

The phonetic spelling string begins in the top left corner of the screen.

C64 BASIC code

C64 screenshot

Try in emulator

Google Sheets, 107 bytes

=let(f,lambda(f,s,if(s="",,left(s)&f(f,mid(s,mid(5686585668555&9657676878575,code(s)-64,1),9^9)))),f(f,A1))

Put the string in cell A1 and the formula in C1. Gets first letters by looking up the offset recursively.

screenshot

Ungolfed:

=let(
  f, lambda(f, s,
    if(len(s),
      left(s) &
      f(f, mid(s,
        mid(
          5686585668555 & 9657676878575,
          code(s) - 64,
          1
        ),
        9^9
      )),
    )
  ),
  f(f, A1)
)

The concatenation operator & gets a string, and takes one byte less than "quotes".

Ruby -pl, 54 52 bytes

Port of l4m2's Node.js port of Neil's Retina solution. -2 bytes from that answer optimizing the regex.

gsub(/([BDHIORT]|N?[CFJOUW]..|[QSVY].)?..../){$&[0]}

Attempt This Online!

Ruby -nl, 80 bytes

My original solution; I just think the way I determine how many letters to skip is neat so it's here for posterity.

i=0;($><<c=$_[i];i+=4+%w"AEGKLMPXZ BDHIORT QSVY CFJUW N".index{_1[c]})while$_[i]

Attempt This Online!

Perl 5 -F, 61 bytes

say@F[0,map$p+=$F[$p]=~y/A-Z/45754745574448546565767474/r,@F]

Try it online!

I could have ported @Neil's solution and gotten this to 51 bytes, but where's the fun in that?

Vyxal 3, 32 bytes

øA‹"-MK,x¬<8≠☷Ṫ“f$iλhϢᑂ$f]lᐐḧσ↻i

Vyxal It Online!

i couldnt figure out cyclical indexing in vyxal so its just a scan fixpoint jank

this might be better in older versions with builtins for fixpoints and whatnot

R, 67 bytes

\(s)gsub("(?=(.))([BDHIORT]|N?[CFJOUW]..|[QSVY].)?....","\\1",s,,T)

Attempt This Online!

Port of l4m2's Node.js port of Neil's Retina solution.

APL+WIN, 93 bytes

Prompts for character string.

c←⎕
a←⎕av[65+⍳26]
n←⍎¨'45754745574448546565767464'
r←⍬
:while 0<⍴c
r←r,↑c
c←n[↑a⍳c]↓c
:end
r 

Try it online! Thanks to Dyalog Classic

Jelly, 24 bytes

OḢị“CṁƝ.ḍ⁹8ɲṠȯ:’D¤⁸ṫµƬZḢ

A monadic Link that accepts a list of characters and yields a list of characters.

Try it online!

How?

OḢị“...’D¤⁸ṫµƬZḢ - Link: list of characters, S
            µƬ   - collect up, starting with S, while distinct, applying:
O                -   ordinals of {Current}
 Ḣ               -   head -> I = ordinal of first character
         ¤       -   nilad followed by links as a nilad:
   “...’         -     65767687857556865856685559
        D        -     to decimal
  ị              -   {I} 1-index, cyclically into {[6,5,7,6,...]}
          ⁸ṫ     -   tail of {Current} from {that} 1-index
              Z  - transpose
               Ḣ - head

Other, similar but more complicated 24's:

ḢȮOị“¥QḌEfṠƇ¤’b5¤+4⁸ṫßḷ¡ (full program)
ḢȮOị“¥QḌEfṠƇ¤’b5¤+4⁸ṫµ¹¿ (full program)
OḢị“¥QḌEfṠƇ¤’b5¤+5⁸ṫµƬZḢ (monadic Link)

Retina 0.8.2, 92 80 49 47 bytes

(?=(.))([BDHIORT]|[QSVY].|N?[CFJOUW]..)?....
$1

Try it online! Link includes test cases. Explanation: Inspired by @Ausername's lookbehind approach. Saved 2 bytes thanks to @l4m2.

(?=(.))([BDHIORT]|[QSVY].|N?[CFJOUW]..)?....
$1

Look ahead to capture and keep the first letter of the word, then skip ahead depending on the first letter(s); BDHIORT words are five letters long, QSVY words are six letters long, CFJUW words are seven letters long, N(O) words are eight letters long, and the rest are four letters long.

Previous 80-byte no-lookahead solution:

(.)(U.B?I?E?T?|RAV?|(OX|OV.|H.)...|O.E|IC?T?E?R?.|[ENS]I?F?..|[CLO].|AN?K?.).
$1

Try it online! Link includes test cases. Explanation:

(.)(...|...).
$1

Keep the first letter of each word, where the alternatives match as follows:

JavaScript (Node.js), 64 62 bytes

s=>s.replace(/([BDHIORT]|N?[CFJOUW]..|[QSVY].)?..../g,x=>x[0])

Try it online!

Based on Neil's solution but js needn't capture the first char in regex

-2 bytes changing regex, which should feed back Neil

Charcoal, 29 bytes

FS¿ω≦⊖ω«ι≔I§”)⧴&Xφ⟧x\`t⊙;g”℅ιω

Try it online! Link is to verbose version of code. Explanation: Port of @Arnauld's JavaScript answer.

FS

Loop over the letters of the input string.

¿ω≦⊖ω

If we're skipping letters then decrement the number left to skip, ...

«ι

otherwise output the current letter, and...

≔I§”...”℅ιω

... use a cyclically indexed compressed lookup table to see how many letters need to be skipped.

JavaScript (ES6), 71 bytes

f=s=>s&&s[0]+f(s.slice("4448546565767464575474557"[s.charCodeAt()%25]))

Try it online!

(or 69 bytes in Node.js)

TinyAPL, 163 bytes

ugh.

⦅⊣⌿⍨1⌽·∨ᑒ/⊣⍷ᐵ⍨'0'∘≠⥼⊆⊢⦆∘"LFA0RAVO0HARLIE0ELTA0CHO0OXTROT0OLF0OTEL0NDIA0ULIETT0ILO0IMA0IKE0OVEMBER0SCAR0APA0UEBEC0OMEO0IERRA0ANGO0NIFORM0ICTOR0HISKEY0RAY0ANKEE0ULU"
⦅⊣⌿⍨1⌽·∨ᑒ/⊣⍷ᐵ⍨'0'∘≠⥼⊆⊢⦆∘...­⁡​‎‎⁡⁠⁤⁣‏⁠‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏⁠‎⁡⁠⁢⁡⁢‏⁠‎⁡⁠⁢⁡⁣‏⁠‎⁡⁠⁢⁡⁤‏⁠‎⁡⁠⁢⁢⁡‏⁠‎⁡⁠⁢⁢⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏⁠‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‏​⁡⁠⁡‌­
              '0'∘≠⥼⊆⊢       # ‎⁡Split big string by '0'
          ⊣⍷ᐵ⍨               # ‎⁢Find each in the argument, returning a boolean list where each beginning of a substring is true
       ∨ᑒ/                   # ‎⁣Or-reduce the masks
    1⌽                       # ‎⁤Rotate the mask by 1 (since the first character is not present in the substrings)
 ⊣⌿⍨                         # ‎⁢⁡Filter the argument by that mask
💎

Created with the help of Luminespire.

Google Sheets / Excel, 158 bytes

Expects input in A1

=REGEXREPLACE(A1,"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",)