[Question]
  [
[Inspired by wezl.](https://chat.stackexchange.com/transcript/message/61328796#61328796)
Your challenge is to take words (sequences of `[a-zA-Z]`) and truncate them to length 3. For example, `never gonna give you up` would become `nev gon giv you up`.
Words will not necessarly be delimited by spaces - for example, [`youtube.com/watch?v=dQw4w9WgXcQ`](https://www.youtube.com/watch?v=dQw4w9WgXcQ) will become `you.com/wat?v=dQw4w9WgX`. Input will be printable ASCII.
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), shortest wins!
## Testcases
```
never gonna give you up -> nev gon giv you up
youtube.com/watch?v=dQw4w9WgXcQ -> you.com/wat?v=dQw4w9WgX
code golf -> cod gol
happy_birthday_to_you -> hap_bir_to_you
*hello world* -> *hel wor*
abcd1234fghi -> abc1234fgh
```
  
[Answer]
# [K (ngn/k)](https://codeberg.org/ngn/k), ~~21~~ 20 bytes
-1 byte thanks to [coltim](https://codegolf.stackexchange.com/users/98547/coltim)!
```
{5>1(1+*)\~"a{"'_x}#
```
[Try it online!](https://ngn.codeberg.page/k#eJwdjEsKwjAYhPc9RYgLtYISrQsF9Qxd6UIIeScQ+5eQNpaiZzdmNzPfzOjzfLySFdnU6+cXsxkv6fuzqCqNcKdGFZCBrmPIuFGhCQY09PjPsowDV1sBr11iUdjbeJFtatLpbh6iLR0BUuW518VZ1vcT5S5EK9lEI9D8UUhtlfeAEgQv65IwLiTZHxptrMM/b4k0OA==)
`{ ... }#` Filter the input using the boolean mask returned by the left function.  
`_x` Convert the string to lowercase.  
`~"a{"'` For each character, is it in `["a", "{")`?  
`1(1+*)\` A scan that converts each 1 to the number of consecutive 1s up to it, incremented by 1. 0s are mapped to 1.  
`5>` Keep the indices where this is at most 4.
[Answer]
# x86-64 machine code, 29 bytes
```
83 C9 FF AC 88 07 2C 41 72 06 24 1F 3C 1A 72 02 31 C9 83 F9 FC 7E EC B0 00 AE E0 E7 C3
```
[Try it online!](https://tio.run/##dVJNj9MwED17fsVQVCnppmXTrVbQUjggceOwXHalXVQ5tpMYOXZkO/0A7V@nTPqlBcHFE795b96zHTGuhNjveWgwwa@DBCaVcQU3WEI5B@Y8KrHNcJxDiNxH41xLsHEyFMAat8ZHL/W3DLkBFrqCaobX21kO7HuB1kWjYlQeGLfy1Ms/AxNNe9hNbw88HU60i4A8tmdvWuDMmB@1x0wzEhuFl2DHQAcXCiN4H7HH7Y@XHK8ipANMF7B2WmKZiJp7HPkMjx@BOvBaW2E6qfB9iFK7Sf3hD8hrW/WYthEbrm2Swk9K1uvDYz59SxfiD3UBbFNrCpmUlYohCRkSnGE/1aYpMJKxMiHz3paxlibHMhkMw4BG9NAzXMAn@4WLWluFwkk1H/Rt4WyI2NmgK6vk6QgtLjH5ZyctF39BgoZIh2cPHF5PH8hbLEft1VW6wFN8ga@W9HifbnrTCzkZaix2UYX0yZKoHf/PlVTP@71Va@WxctZyrPRa4c512LVAJXaFmgjXvNnwKOqP66W828w27@6rB3EH/XFJZkqoedvuVoX2sZZ8t4puRVoY1coYhxvnjRwBL4TMpzezsqo1/BKl4VXYj5vbGS30ny8puzK/AQ "C (gcc) – Try It Online")
Following the standard calling convention for Unix-like systems (from the System V AMD64 ABI), this takes in RDI an address at which to place the result, as a null-terminated byte string; and the address of the input, as a null-terminated byte string, in RSI.
In assembly:
```
f:
    or ecx, -1
startloop:
    lodsb
    mov [rdi], al
    sub al, 0x41
    jb notletter
    and al, 0x1F
    cmp al, 26
    jb isletter
notletter:
    xor ecx, ecx
isletter:
    cmp ecx, -4
    jle startloop
    mov al, 0
    scasb
    loopnz startloop
    ret
```
[Answer]
# [Python](https://www.python.org), 52 bytes
```
lambda s,c=0:[i for i in s if(c:=-~c*i.isalpha())<4]
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m72soLIkIz9vweI025ilpSVpuhY3TXISc5NSEhWKdZJtDayiMxXS8osUMhUy8xSKFTLTNJKtbHXrkrUy9TKLE3MKMhI1NDVtTGKhelUKijLzSjS00jSUEp2cXVLjE5OSgTg-Md5QSVOnOLXAVklJE6J2wQIIDQA)
Outputs as a list of characters.
If that's not allowed:
## [Python](https://www.python.org), 58 bytes
```
lambda s,c=0:"".join(i*((c:=-~c*i.isalpha())<4)for i in s)
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m72soLIkIz9vweI025ilpSVpuhY3rXISc5NSEhWKdZJtDayUlPSy8jPzNDK1NDSSrWx165K1MvUyixNzCjISNTQ1bUw00_KLFDIVMvMUijUhJuwpKMrMK9FI01BKdHJ2SY1PTEoG4vjEeEMlTaiSBQsgNAA)
[Answer]
# [Zsh](https://www.zsh.org/), 39 bytes
```
<<<${1//(#m)[a-zA-Z](#c3,)/$MATCH[1,3]}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m724qjhjwebi1JL8ghKF1IqS1LyU1JT0nPykpaUlaboWN9VtbGxUqg319TWUczWjE3WrHHWjYjWUk411NPVVfB1DnD2iDXWMY2shyhdAqC3RSolOzi6p8YlJyUAcnxhvqBQLlQMA)
[Answer]
# [JavaScript (V8)](https://v8.dev/), 39 bytes
```
x=>x.replace(/(?<=[a-z]{3})[a-z]/gi,"")
```
[Try it online!](https://tio.run/##JY7BboQgGITvfQrCCbVq2vXQJsv6DJ62SdOYX0CgYYWwiNqmz27JepuZbzKZb4hwZ167UMa3faT7Si9r5YUzwASpSXumn1D@fP2e/rKHqKV@xjjbJU1N5/UUyFpgVF4QLkayZtmTJHgSUXgk7TQBkjoKtNkZzQ4/YNJhHkTF7K1eIDDVRsq7pVner/KDdUeJWS7SgBkPq8C5rR@0D4rD1gfbp5UD5UoYY9FiveH5EcHA@MvrqRml0unqPw "JavaScript (V8) – Try It Online")
Pretty straightforward.
```
x=>x.replace(/(?<=[a-z]{3})[a-z]/gi,"")
x=>x.replace(                      ,  )  // standard regex replace setup
             /                  /gi      // case insensitive, replace all occurences of
                           [a-z]         // an alphabetical character
                                    ""   // with the empty string
              (?<=        )              // given that it is immediately following
                  [a-z]{3}               // 3 consecutive alphabet characters
```
[Answer]
# BQN, 22 bytes
```
⊣/˜3≥·(×+⊢)`2|"A[a{"⊸⍋
```
[Try it here!](https://mlochbaum.github.io/BQN/try.html#code=RiDihpAg4oqjL8ucM+KJpcK3KMOXK+KKoilgMnwiQVtheyLiirjijYsKCuKAolNob3fiiJhGwqgg4p+oCiJuZXZlciBnb25uYSBnaXZlIHlvdSB1cCIKInlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EiCiJjb2RlIGdvbGYiCiJoYXBweV9iaXJ0aGRheV90b195b3UiCiIqaGVsbG8gd29ybGQqIgoiYWJjZDEyMzRmZ2hpIgrin6kKCkA=)
-5 bytes thanks to @ovs!
## Explanation
* `⊣/˜...` filter input by constructing this binary array...
* `2|"A[a{"⊸⍋` for each char, 1 if alphabetical and 0 otherwise
	+ more literally: check if ordering the char into `A[a{` will yield an odd index
* `(×+⊢)`` count consecutive runs of 1s
* `3≥·` for each element, check if >= 3
Example of how the input is manipulated under the hood:
```
never gonna give you up  # input
11111011111011110111011  # 2|"A[a{"⊸⍋
12345012345012340123012  # (×+⊢)`
11100111100111101111111  # 3≥·
nev██ gon██ giv█ you up  # ⊣/˜
```
[Answer]
# [brev](https://idiomdrottning.org/brev), 81 bytes
```
(print (strse (read-line) '(+ alpha) (as-list (fn (take x (min (length x) 3))))))
```
I would've wanted:
```
(print (strse (read-line) 'word (as-list (fn (take x (min (length x) 3))))))
```
but that YouTube example looks differently.
Reading and writing stdin/out adds 13 bytes, it's just 68 as a function:
```
((over (strse x '(+ alpha) (as-list (fn (take x (min (length x) 3))))))
 '("never gonna give you up"
   "youtube.com/watch?v=dQw4w9WgXcQ"
   "code golf"
   "happy_birthday_to_you"
   "*hello world*"
   "abcd1234fghi"))
```
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal) `s`, 7 bytes
```
øWƛL3∵Ẏ
```
[Try it Online!](https://vyxal.pythonanywhere.com/#WyJzIiwiIiwiw7hXxptMM+KIteG6jiIsIiIsImhhcHB5X2JpcnRoZGF5X3RvX3lvdSJd)
Would be 5 bytes if not for modular indexing. Undone by something otherwise useful, I say!
## Explained
```
øWƛL3∵Ẏ
øW      # Split the input on words (/[A-z]+/). Numbers and punctuation are left as single character strings.
  ƛ     # To each "word":
   L3∵  #   get the minimum of the length of the word and the number 3. This is needed to account for modular indexing. This would otherwise just be `3`
      Ẏ #   get the first amount of characters of the word, where the number of characters is the number we just calculated.
# the s flag joins everything into a single string before printing it.  
```
[Answer]
# [R](https://www.r-project.org), 38 bytes
```
\(x)gsub('([a-z]{3})[a-z]+','\\1',x,T)
```
[Attempt This Online!](https://ato.pxeger.com/run?1=TZBLboMwFEWVSQdZhUc1ENIqIYNmgLKGSJFSqUTI-ItEMSI2hFZdSSc0UhfVriY2GCkjv3fPeXfg75-6v7L4Vyu2fPl7TLyLz88686D3hpYfp8_oyx-GBQxhkqxgeAkP_mj_zx6YB0va0BpwWZYI8LyhoJMa6Ar6II6BpZZZMoG5OTKj0hl9wvL9uUUKi10Tk327abdH_or37thYk3HPhwYsCTXNBXOu2e06MIGqqkuzvFaCoC5VMjVNzjPMkim0eiBoUUjQyroggdNsZpNgMFCGyWodbRgXuRNM5BI4H7-j78f3Bg)
-2 bytes thanks to pajonk!
Direct application of `gsub`.
[Answer]
# [Perl 5](https://www.perl.org/) `-p`, 17 bytes
```
s/\pL{3}\K\pL*//g
```
[Try it online!](https://tio.run/##TY3LDoIwEEX3/YquSQDxsXChfoC6cKULElLa2pJUpsECIcZft84kmLiauefcab3u3CbGZ17602v1Lo84kzw3MbZ60B030LaCm2bQfIKe956ne46KBOGZMhyhr3Um4ZGPIkh7GHbqMq7H7dXc5IWusPLT/5JJUBqfc3cqYaCdWeH9VNVNF6wSUxWgoo@wgILwTFhitXPAR@icSsgToJgwUUtVLFfru7ENGcxz/IAPDbTPmPqYnjfZolh8AQ "Perl 5 – Try It Online")
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), 21 bytes
```
i`([a-z]{3})[a-z]+
$1
```
[Try it online!](https://tio.run/##HcuxDsIgFEDRna9gcNAaNbVdHIzf0EkTY@orvAIJ8hoCJWj8dmyc7l2Ox2AclGKe6zvs3o9P8938Z8tWdSkOZ/RckXPAlZmRZ4o8TmxJiAPuBb0OCYLQl/ksu9Sm01XdRMcESVyYHZmGacr9YHzQEnIfqF8sqzRaSzyRt7JiMAhZH5t2VNr8AA "Retina 0.8.2 – Try It Online") Link includes test cases. Explanation: Case-insensitively matches runs of three letters followed by at least one more letter and keeps only the first three.
[Answer]
# [Python](https://www.python.org), 84 bytes
```
lambda s:''.join([w,w[:3]][w.isalpha()]for w in re.split('([^a-zA-Z])',s))
import re
```
[Attempt This Online!](https://ato.pxeger.com/run?1=VY9PSsQwFMb3c4rskg5tRWcWWhjEIwwIirUOaZM0kTQvpGlDvYqbguh53HobM8wg9m0efH9-8L1_2clLMPOH2D1_Dl5k1z_3mnY1o6gvMM5fQRlShjSUxaaqypCrnmorKUkqAQ4FpAxyPO-tVp5gUr7Q7O0ue6oSnPZJslKdBedj4sz-Ppb6Y6nEho_coRaMoahVI0cTDGiwOEUr9Hc4in6oed5AdxGob-TtuGP7sA03D-1js8fp_3ADjEeiFktZUmunQ62cl4xOBw-HSF1G1pJrDSiA02y9tGjdsMurzVa0UuGqiJZ1yngiSFx42jXPp_8L)
[Answer]
# [Factor](https://factorcode.org/), ~~58~~ ~~50~~ 48 bytes
```
[ R/ [a-z]+/i [ 3 short head ] re-replace-with ]
```
[Try it online!](https://tio.run/##ddHBSsQwEAbge59izLHSLbp7UVGP4kVYRRRKKWkybQLdJqZpaxWfvSami6uwcwrM988MpKLMKjM/P90/3F2CwRrfNXT41mPLsANt0NpJG9lauIqizwhckRYHNFCrtqVQywFhUj30msC@TiC5Aae88WIBIe3eti9xxdQuHall4na45ttxM1681K9sS0Laqb047IcRTHF0s5vqd@Xf@hnhlEchIqjWU1FKYwWnU2FV4TaQ/xGnvFnaIRkLbBoFozINj8mxZV55E4cQLRk/O19vqlpIcvRCpxYUfUVzBo8pZDT5yE9TCRmsoRPKWBBIOeTucxKDuqEMk1FaAfm8oxpW8zc "Factor – Try It Online")
[Answer]
# [Python](https://www.python.org), 57 bytes
```
lambda s:re.sub('([a-z]{3})[a-z]+',r'\1',s,0,2)
import re
```
[Attempt This Online!](https://ato.pxeger.com/run?1=VY9LasMwGIT3OcW_k50qSfNYNIHQM2SVQhKMrIclkCWhh41bepJuDKU9T7e9TU0TSj2bf5gZPvjfPl0XpTX9u9ifP1IUs4fvrSZ1yQiEnefzkMoMZScye768rF_zX3OHsEfnJcIB3-NVPlG1sz6C5zfAl7AeAigDJ2R4wz1U1hgClWo4dDZBcgjDBP6EhjCmks-prRctiVQ-Nnt2aDft9lg90QPC_8fUMj4QtRjHkjjXFaXyUTLSFdEWA3U8mUqutYXWes2m44qUlC1X642opEKX3VA5r0zMRBby_PpX31_vDw)
A straight port of my regex [R solution](https://codegolf.stackexchange.com/a/248779/98085). `re.IGNORECASE` is 2.
Framework taken from solid.py's answer.
[Answer]
# [Pip](https://github.com/dloscutoff/pip), ~~38~~ 25 bytes
Simple regex solution, matches runs of letters and captures the first 3, replacing matches with the capture group.
```
aR-`([A-Z]{3})[A-Z]*``\1`
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m724ILNgebSSbkG5UuyCpaUlaboWOxODdBM0oh11o2KrjWs1wQythIQYwwSIPFTZ7milvNSy1CKF9Py8vESF9MyyVIXK_FKF0gK4SQA)
[Answer]
# [C (clang)](http://clang.llvm.org/), ~~78~~ 65 bytes
```
c;*p;f(*s){for(c=0,p=s;*s;p+=c<4)c=iswalpha(*p=*s++)?c+1:0;*p=0;}
```
[Try it online!](https://tio.run/##bZFfb5swFMXf@ynukCqBSdakzR5ayvow7a0vfdqkJoqciw2ojm1hJySL8tXHbP4kqBoSYB@fe/yzL05RUJk3DSZEJzwkJjpxVYWYziY6NQkxiY5TfF5EmJampkIXNCQ6JSaOoxeM508zV5jOknNTSgtbWsowgtMNuMcJBCwz1ryvIIXTayDZnlWQKykp5OWewVHtYKeDCbwGbmh3G/YV1fauphaLl32avdWL@vFX/hvfWg@qjLlywdtZQbU@rjdlZYuMHtdWrV1Gu0IKJoSCWlUiI61CN5jN7x8WPC/K4Jxc@dhBM7QsGyF6QI/3iW4gG3MNVB5qYPJEn2E8ygWk5xgwUEljAQtaEfdl@MGqDiZYHn7eLw@PP9z7zRWP5w9DtWsWhP7qS5mxgyubJf3wGUz5hykeDkeM7nqBXJQE4rh1R21Y17dr71xc17/Ws0rGy7DZcf5eoxFMhjaCGOYjg9NRH0PvmYCNrgu81UZCd3Dmtrq04n@7aWqM83zxwVvdB7NRjq6cjYfBrTAw/Q7@d2uW0t2bnUBnH27XZ6360vPNufmLXNDcNNP6Hw "C (clang) – Try It Online")
*Saved a whopping 13 bytes thanks to [Neil](https://codegolf.stackexchange.com/users/17602/neil)!!!*
Inputs a wide character string.  
Performs the word truncations in place.
[Answer]
# [Ruby](https://www.ruby-lang.org/), 31 bytes
```
->s{s.gsub(/[a-z]+/i){$&[0,3]}}
```
[Try it online!](https://tio.run/##KypNqvyfZvtf1664ulgvvbg0SUM/OlG3KlZbP1OzWkUt2kDHOLa29n@BQlq0Ul5qWWqRXlJqap5CaUF8SUZqUaqOno6xiaGOUux/AA "Ruby – Try It Online")
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 10 bytes
```
=ŒskŻḣ€4FḊ
```
[Try it online!](https://tio.run/##y0rNyan8/9/26KTi7KO7H@5Y/KhpjYnbwx1d/w@3a0b@/6@Ul1qWWqSQnp@Xl6iQnlmWqlCZX6pQWqCko6AEZJWUJqXqJefn6pcnliRn2JfZpgSWm5RbhqdHJAeClCTnp6QCNeekgTgZiQUFlfFJmUUlGSmJlfEl@fFAE0ASWhlAV@QrlOcX5aRogQQSk5JTDI2MTdLSMzKVAA "Jelly – Try It Online")
It's absolutely hideous, but the most elegant thing I've come up with is a byte longer: `nŒs‘×¥\<4x@`
```
    Ż         Prepend a 0 to the input, and
   k          partition that after indices where
=             the original input equals
 Œs           itself case-swapped.
     ḣ€4      Keep the first 4 elements of each slice (one non-letter + up to 3 letters).
        F     Flatten,
         Ḋ    and remove the 0.
```
[Answer]
# [Stax](https://github.com/tomtheisen/stax), 7 [bytes](https://github.com/tomtheisen/stax/blob/master/docs/packed.md#packed-stax)
```
îªZ╛▲?↕
```
[Run and debug it](https://staxlang.xyz/#p=8ca65abe1e3f12&i=never+gonna+give+you+up+%0Ayoutube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ+%0Acode+golf+%0Ahappy_birthday_to_you+%0A*hello+world*+%0Aabcd1234fghi+%0A&m=2)
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 15 bytes
```
ΦθΦ⁴¬№α↥§⁺×_μθκ
```
[Try it online!](https://tio.run/##LYzLCsIwEEX3fsXQ1RTizp0rKShupIu6lpCMNTjJtHmI9OdjRS8cOHDgmoeORjTX2kcXMh4dZ4o4K/jbTsFFMnZS1qoVXKeJotGJ8JDPwdIbey4JB@cpYXNrFPhWwbzybH/bf79ljNp7F0boy7IwJdDBQieW4CR839Ttiz8 "Charcoal – Try It Online") Link is to verbose version of code. Explanation: Generates all overlapping substrings of up to four characters ending at each character and keeps those containing at least one non-letter.
```
 θ              Input string
Φ               Filtered by
   ⁴            Literal integer `4`
  Φ             Any value satisfies
      α         Predefined variable uppercase alphabet
    ¬№          Does not contain
           _    Literal string `_`
          ×     Repeated by
            λ   Current value
         ⁺      Concatenated with
             θ  Input string
        §       Indexed by
              κ Current index
       ↥        Uppercase
                Implicitly print
```
Note that I use `Filter` instead of `Any` because the latter does not implicitly convert an integer to a range.
[Answer]
# [Pyth](https://github.com/isaacg1/pyth), 15 bytes
```
sf<=Z*hZ}rT0G4Q
```
[Try it online!](https://tio.run/##K6gsyfj/vzjNxjZKKyOqtijEwN0k8P9/pYzEgoLK@KTMopKMlMTK@JL8@Mr8UiUA "Pyth – Try It Online")
Port of [pxeger's Python answer](https://codegolf.stackexchange.com/a/248771/65425)
[Answer]
# [Julia](https://julialang.org), ~~46 bytes~~ 42 bytes
~~```
f(s)=replace(s,r"([\p{L}]{3})[\p{L}]*"=>s"\1")
```~~
We do not need the square brackets, thx to @thejonymyster:
```
f(s)=replace(s,r"(\p{L}{3})\p{L}*"=>s"\1")
```
[Attempt This Online!](https://ato.pxeger.com/run?1=vZO_b9NAFMcHtvsrnq4SSiInUdsgCpILA2OXTjBUii7284_WORvfOSGpylAGFhATEwOpSAa2glp-SN38DzgjTP5TuBc7qEjtysnS3Xuf7_fde5Lvw-Iwi0Ix-33n7gYEWifqYbfrxC76ceR1lBbOEb5wAiF97DjxsPs8Q6XDWKruVm_n_r3trk4z6QiN7XGcuqodyrZoK5QapYOMuUILm3POJI4wBT-WUoAfjhAmcQZZAu1dMIgApessM5vOBtWNY6Gd4NHIdvfHvfGDp_4zZ59cRrLG1yGj3oGaJ5EJ6MwCkSST_iBMdeCKSV_HfbrICAygdJ1hrQCjKAYzSuS2iFOCwhYTA8fd3NrueX4QEjFxHdazmVWN1zfrphkrwV-8nhVhFEb5GaFAQH6l1RS0kJP8TFsQ5J9NbKqraX4VHebfJAzRBzGFlcKl2qsCay9ZK9vKck3NillxXlzA8rS4LL4s30HxtfhRXBSXy9PlG6rzD68pK-c_y_l5uXgN5fx9uXhVzr-Xi7fl_BPcTqwbtLd71yfTwX-7jD3JYJjlHzW4GErYwwFKyOfSxVR2qJOaEya6Yh1GP_Ii015751fLa6imnWISCQcbykp54yA53js53j5prg4tbu8qfrDJm7XjpRenEJnbzKeSKNQNehwWP5DcOkJMcJjoie2JSGGTgVElFppnYFdaY7Q4dcYJbiRpKHUkG6TiwFdKAo-FUpjqhkekadtVHqVb9z2bVfsf)
`\p{L}`: <https://stackoverflow.com/questions/3617797/regex-to-match-only-letters>
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), 12 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
.γa}DaÅÏ3£}J
```
[Try it online](https://tio.run/##yy9OTMpM/f9f79zmxFqXxMOth/uNDy2u9fr/vzK/tKQ0KVUvOT9XvzyxJDnDvsw2JbDcpNwyPD0iORAA) or [verify all test cases](https://tio.run/##yy9OTMpM/V9Waa@k8KhtkoKSfeV/vXObE2tdEg@3Hu43PrS41uu/zv9opbzUstQihfT8vLxEhfTMslSFyvxShdICJR0lIKOkNClVLzk/V788sSQ5w77MNiWw3KTcMjw9IjkQqCI5PyUVqDUnDcjOSCwoqIxPyiwqyUhJrIwvyY8H6geKa2Wk5uTkK5TnF@WkaAH5iUnJKYZGxiZp6RmZSrEA).
**Explanation:**
```
.γ }          # Adjacent group the (implicit) input-string by:
  a           #  Letters
    D         # Duplicate this list of groups
     a        # Check which groups only consist of letters
      ÅÏ  }   # Apply on the truthy indices:
        3£    #  Keep up to the first 3 characters
           J  # Join all groups back together to a string
              # (which is output implicitly as result)
```
[Answer]
# [Lua](https://www.lua.org/), 41 bytes
```
print(((...):gsub('(%a%a?%a?)%a*','%1')))
```
[Try it online!](https://tio.run/##DcLBCoAwCADQX/EiasSga5e@xWCMQbixctDXW493uUb0Ue1h5pSS7OX2k4lRUY@/oC60Em4kIhFheeYBpZkplDozvM3B@wc "Lua – Try It Online")
[Answer]
# [sed](https://www.gnu.org/software/sed/) -E, 24 bytes
```
s/([A-Z]{3})[A-Z]*/\1/gi
```
[Try it online!](https://tio.run/##Hcu9DsIgFEDhnadg1CaV1HZxMMbBB@ik8ScNhSuQIJe0UNIYX11snM5ZvhFkqVzMeWSr27G8Pt71Z/2fgt0rpkzODiYYqELnOFVmAjpjpNGTJSH2sBH4YokHoQ/TXrapSbuzuoiWCJSwMPskmns/d70ZgpZ87gJ2iyWFBmuRJhysLAjvhay2dfNU2nzRB4NuzOXpBw "sed – Try It Online")
[Answer]
# [Raku](https://raku.org) -p, 20 bytes
### (formerly known as Perl\_6)
```
s:g/<:L>**3<(<:L>*//
```
FYI, Raku regexes tolerate whitespace by default, so a more readable (exploded) version would be:
```
s:g/ <:L>**3 <( <:L>* //
```
[Answer]
# [Rust](https://www.rust-lang.org/), 109 bytes
```
fn f(s:&str)->String{let mut n=0;s.chars().filter(|c|if c.is_alphabetic(){n+=1;n<4}else{n=0;true}).collect()}
```
[Try it online!](https://tio.run/##NVDLTsMwELz3K5YcKju0gUIuUFq@oeIAEkKR42xiS64d2ZtGVepvLy4ox3ns7Gj8EOh6bS20LLwuA3m@3n@Q17abDBIcBwK7e9yGQirhA@NFqw2hZxd50S3IQodKmF6JGklLxid7v9ts7VsZ0QScbqfkB4y8kM4YlMR4vH07Cm0Zh2kB0DoPAbSF5XdCAJnFE3ronLUCOn1COLsBhj5b/csJ0VBjCjw@jIKkej/tmsNYji@f3Zc8zDbpGkwhpp0JJfr@XNXak2rEuSJXpaRZzBUa42B03jT5TIpaNpun57JTOvv56wrQp2nI2DuWTRHWe5hitoI8rNJ@eeB8m0xxEa@/ "Rust – Try It Online")
[Answer]
# [J-uby](https://github.com/cyoce/J-uby), 29 bytes
Port of [G B’s Ruby answer](https://codegolf.stackexchange.com/a/248793/11261).
```
~(:gsub+(~:[]&3&0))&/[a-z]+/i
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m700K740qXLBIjfbpaUlaboWe-s0rNKLS5O0NeqsomPVjNUMNDXV9KMTdatitfUzIWq2F5SWFCu4RStpZaTm5OQrlOcX5aRoKcVCZBcsgNAA)
## Explanation
```
(~(:gsub +               )               # replace
                           & /[a-z]+/i)  # each word
           (~:[] & 3 & 0)                # with its first three characters
```
[Answer]
# [Scala](https://www.scala-lang.org/), 54 bytes
Golfed version. [Try it online!](https://tio.run/##RY3NasMwEITvfopF5CCFJqVNLjV1Qx6gh1BKCyEEWZJlFUUysvxX42d3VSfEt53Zb2ZKRjUdbfojmId3qgz0EQAXGVyCwNTJMoa9c7Q7fninjDyRGD6N8pBAP/5zGW7j64sk7dqJQlMm9lpjhHevyZGufk/9ZiDTgR4AITKGheuGDFm4he@1RZBeG1yiRQurN1j0YYIMiERTTmJkRC0cSGsMBalqAZ2toCoCcQOC9lUq1sxeHhvqWb6rE35ots3Ll/xmhxlklotQpLPZymlRdOdUOZ9z2p29PYe2@b3MhdYWGus0X842TRl/et5sM5mryR2iYfwD)
```
def f(x:String)=x.replaceAll("(?<=[a-z]{3})[a-z]", "")
```
]