[Question]
  [
My dog is called Rex. Every time I scold him, he seems not very impressed and the only times I see him react is when I pronounce his name. If I say 
`Rex, I told you not to do this! You're making me angry Rex!`
all he hears is 
`Rex, * **** *** *** ** ** ****! ***'** ****** ** ***** Rex!`
**The challenge** : given an input string, your program must output the same string where all alphabetic characters have been turned to stars, except the characters in the appearances of the word `Rex`, who must be left untouched. The non-alphabetic characters are also left untouched.
**Details** : The challenge is case-insensitive, thus `rex` must be left untouched also. The word `Rex` can be part of another word, so for example `anorexic` must be rendered as `***rex**`.
**Update** : as the initial text of this challenge did not clarify how underscores or numbers or accentuated characters should be treated, I do not make any special requirement on those characters. Thus, a solution is valid as long as characters in `a-zA-Z` (and also the one mentioned in the examples, `,!".`) are handled correctly.
Test cases :
Input : `Rex lives in Rexland.` 
Output : `Rex ***** ** Rex****.`
Input : `To call Rex, just say "Rex".` 
Output : `** **** Rex, **** *** "Rex".`
Input : `My cat is getting anorexic.` 
Output : `** *** ** ******* ***rex**.`
  
[Answer]
## \*\*REXX ~~151~~ ~~148~~ 141 bytes \*\*
(Kinda seemed appropriate)
```
i=arg(1)
m=i
o=translate(m,'',xrange('A','z'),'*')
p=0
do forever
   p=pos('REX',m,p+1)
   if p=0 then leave
   o=overlay(substr(i,p,3),o,p)
end
say o
```
[Try it here](https://www.tutorialspoint.com/execute_rexx_online.php "Try it here")
Notes for non-REXXers:
1. translate is a character replacement function (name comes from an assembler instruction on IBM MF). It searches string1 for the characters in string3. Every time it finds one it replaces it with the same positioned one in string2. If string2 is too short it is padded with the pad character.
[See here for translate function](http://www.rexxinfo.org/html/functions.html#translate)
2. overlay simply overlays the string1 on top of string2 at the specified position.
[See here for overlay function](http://www.rexxinfo.org/html/functions.html#overlay)
[Answer]
## [Retina](https://github.com/m-ender/retina), ~~24~~ 21 bytes
```
i`(rex)|(\w)
$1$#2$**
```
[Try it online!](https://tio.run/nexus/retina#U9VwT/ifmaBRlFqhWaMRU67JpWKoomykoqX1/39QaoVCTmZZarFCZp4CkJOTmJeixxWSr5CcmJMDEtBRyCotLlEoTqxUUAJylfS4fCuBkiUKmcUK6aklJZl56QqJeflAszOT9QA "Retina – TIO Nexus")
### Explanation
Skipping `rex`s is easiest by matching them as well, because matches can't overlap. So if we give priority to `rex` over other letters, those will be covered in a single match and not touched by the individual-letter matches.
But how do we do different things depending on the alternative that was used for the match? Unfortunately, Retina doesn't (yet) have any conditional substitution syntax like the Boost regex flavour. But we can fake it by including both substitutions in a single replacement and making sure that only one of them is non-empty:
* `$1` is the first capturing group, i.e. the `(rex)`. If we did match `rex` this simply writes it back (so it does nothing), but if we didn't match `rex` then `$1` is an empty string and vanishes.
* `$#2$**` should be read as `($#2)$*(*)`. `$#2` is the number of times group `2` was used, i.e. the `(\w)`. If we matched `rex` this is `0`, but if we matched any other individual letter, this is `1`. `$*` repeats the next character as many times as its left-hand operand. So this part inserts a single `*` for individual-letter matches and nothing at all for `rex`.
[Answer]
# JavaScript (ES6), ~~42~~ ~~41~~ 38 bytes
```
s=>s.replace(/rex|\w/gi,m=>m[1]?m:"*")
```
---
## Try It
```
o.innerText=(f=
s=>s.replace(/rex|\w/gi,m=>m[1]?m:"*")
)(i.value="Rex, I told you not to do this! You're making me angry Rex!")
oninput=_=>o.innerText=f(i.value)
```
```
<input id=i><pre id=o>
```
---
## Explanation
```
s=>            :Anonymous function that takes the string as an argument via parameter s.
s.replace(x,y) :Replace x in s with y.
/rex|\w/gi     :Case-insenstive regular expression that globally matches all occurrences
                of "rex" or any single letter, number or underscore.
                (numbers & underscores will never be included in the input.)
m=>            :Anonymous function that takes each match as an argument via parameter m.
m[1]?          :If string m has a second character, ...
                (Equivalent to m.charAt(1))
m              :Return m, ...
:"*"           :Otherwise return "*".
```
[Answer]
# [APL (Dyalog Unicode)](https://www.dyalog.com/), 22 [bytes](https://codegolf.meta.stackexchange.com/a/9429/43319 "When can APL characters be counted as 1 byte each?")[SBCS](https://github.com/abrudz/SBCS ".dyalog files using a single byte character set")
```
'rex' '\w'⎕R'\0' '*'⍠1
```
[Try it online!](https://tio.run/nexus/apl-dyalog#PY4xDoJAEEV7T/GhmcQYorfQwobYmNBMYIOry27CDspewE5jY@/ZuAguJlK@/Df/z7hV3A73F7WqJ1Bxo@H5zqlYR1jS8PhsxnFSQLnqV9hBnKkQXAfrJAIqBzlpn@DoOootaPiibY1GgW3dBsS7hBZzB4y@Kg9tp8CwrbJ/eHAo2Rj8hs6dF3gOSCOms7MP0RFoj1qJTDtsXXxdlxl9AQ "APL (Dyalog Unicode) – TIO Nexus")
Simple PCRE **R**eplace.
`⍠1` sets case insensitivity. Simply replaces `rex` with itself and all other word characters with asterisks.
[Answer]
# [Perl 5](https://www.perl.org/), 24 bytes
23 bytes of code + `-p` flag.
I used Martin Ender's regex from his [Retina answer](https://codegolf.stackexchange.com/a/119734/55508) (which happens to be shorter in Perl, thanks to `\pl`), and only had to adapt the right side of the s///.
```
s%(rex)|\pl%$1//"*"%gie
```
[Try it online!](https://tio.run/nexus/perl5#U1YsSC3KUdAt@F@sqlGUWqFZE1OQo6piqK@vpKWkmp6Z@v9/UGqFQnJiiUJmsUJ6aklJZl66QmJePlBtZrIeAA "Perl 5 – TIO Nexus")
[Answer]
# [Retina](https://github.com/m-ender/retina), ~~32~~ 31 bytes
```
iS`(rex)
%iT`Ll`*`^(?!rex).*
¶
```
[Try it online!](https://tio.run/nexus/retina#U9VwT/ifGZygUZRaocmlmhmS4JOToJUQp2GvCBLR0@I6tI3r//@g1AqFnMyy1GKFzDwFICcnMS9FjyskXyE5MScHJKCjkFVaXKJQnFipoATkKulx@VYCJUsUMosV0lNLSjLz0hUS8/KBZmYm6wEA "Retina – TIO Nexus") Explanation: Splits the string into occurrences of the word `rex` and everything else, but keeps the matches. Then, on lines that don't begin `rex` (i.e. the "everything else"), change letters to `*`s. Finally, join everything back together.
[Answer]
## C, ~~99~~ ~~97~~ ~~92~~ ~~86~~ ~~74~~ ~~73~~ ~~72~~ 65 bytes
```
f(char*s){*s&&f(s+=strnicmp("Rex",s,3)?!isalpha(*s)||(*s=42):3);}
```
Pelles IDE environment provides (compile with /Go) the function strnicmp. This function is identical to strncasecmp. See it [work here](https://tio.run/nexus/c-gcc#jZBNbsIwEIX3nOI1C2STqEXQbppGPUE3VXcBVVbigKvgRBkHQUPOntoWLSD1bxaj8Ty/z@MZCpatRTMh3k1oPC4YhQmZRmeCZLapWfAsd0FE0Zw/XikSZb0WzF4@HGxObmf8fs7jflDaYCOUZthWKgcfdSPYcGTkwoh0mc7upksk6OCVH6KDew@l2kqC0rCHUuj8OkCP6A/jS4VMlKXzRHhryYDEHgsHXAT/IjztLcFAEVbSGKVXELpq5E5lv9t7xF7yya3Cffk1q1pbJiD1LquC@SY4bi4aqV0KP7cXVcM8Q@ncbiLBFPGxfjjnHpthaJftx/8a7pPs9RPdRd0a@l7tTxOM@uED) (with the replacement function).
The output is stored in the first parameter which is an in/out parameter.
Thanks to [Johan du Toit](https://codegolf.stackexchange.com/users/41374/johan-du-toit) for letting me know that recursion is slightly shorter.
[Answer]
# Ruby, ~~36~~ ~~35~~ 32 bytes
```
->s{s.gsub(/(rex)|\w/i){$1||?*}}
```
As a test:
```
f=->s{s.gsub(/(rex)|\w/i){$1||?*}}
tests = [
  ["Rex, I told you not to do this! You're making me angry Rex!", "Rex, * **** *** *** ** ** ****! ***'** ****** ** ***** Rex!"],
  ["Rex lives in Rexland.", "Rex ***** ** Rex****."],
  ["To call Rex, just say \"Rex\".", %q(** **** Rex, **** *** "Rex".)],
  ["My cat is getting anorexic.", "** *** ** ******* ***rex**."]
] 
tests.each do |input, output|
  if f.call(input) == output
    puts "Fine for #{input.inspect}"
  else
    puts "Problem with :\n#{input.inspect}"
    puts f.call(input)
    puts output
  end
  puts
end
```
It outputs:
```
Fine for "Rex, I told you not to do this! You're making me angry Rex!"
Fine for "Rex lives in Rexland."
Fine for "To call Rex, just say \"Rex\"."
Fine for "My cat is getting anorexic."
```
[Answer]
# PHP, 78 Bytes
```
<?=preg_replace("#[a-df-qs-wyz]|r(?!ex)|(?<!r)e|e(?!x)|(?<!re)x#i","*",$argn);
```
[Try it online!](https://tio.run/nexus/php#NY9BT4NAEIXv/Ipha8JigD8AysH00IOamF5M2zQbmMLqdhdnFwVF/zouNR7fvHlf3ivKru0CJDJ0JOwMOakb/rM@PjxuN3frOA9OhlBULd@xJxwS2IAzqobR9KCN8wJqA66VNoRn00eEcBavngFnBKEbGsHHQpYESxyUfEcLUi9HJXSdeSPaGqiEUnDhv/TWgRUjLP8si3zwfvS@A2mhQbf082BfapBVxg7CXglqdPxV3s5FedMRNssQJSrkbLUTaX1K32z6MX4eJuJliEM88bIIKcYJvf6XGA8ryRJ2zZI/YD5j1Rq213vN8u/5Fw "PHP – TIO Nexus")
# PHP, 84 Bytes
```
<?=preg_replace_callback("#(rex)|\pL#i",function($t){return$t[1]?$t[1]:"*";},$argn);
```
-1 Byte `\w` instead `\pl` in this case underscore and numbers are replaced too 
`\pL` is shorter as `[a-z]` or `[[:alpha:]]`
[Try it online!](https://tio.run/nexus/php#JY9Na8MwDIbv@RWqG0gyQmDXpVsOo4fCPmD0MpoSPEdNvLp2kJ3R0G1/PbO7i0Dvx4O0qoZ@iJDIUEM4GHJSd@nvunl53W4e11kZHQwhF326Y294zmEDzqgWJjOCNs4v0BpwvbQLeDdjQggnfvQMOCFw3dEEvrZgeRTqoOQXWpA6iIrrtvBGsjUguFJw5X@O1oHlE4Q8KxJffJ6870Ba6NCF@zzYH3WWomB7bmNOnc4u1cO8qu4Hwi48orjAJlA/uDimbJn6fPZdD09LyfLDqIWTRqexyy6EbiQdu93tvrrOO3bDyp/8H1vOKHrDal1rL85/ "PHP – TIO Nexus")
[Answer]
# C (GCC on POSIX), ~~167~~ ~~118~~ ~~93~~ 87 bytes
```
i,j;f(char*s){for(i=0;j=s[i];i++)strncasecmp("Rex",s+i,3)?s[i]=isalpha(j)?42:j:(i+=2);}
```
[Try it online!](https://tio.run/nexus/c-gcc#LY7NCsIwEIRfZfGU2LT4dzIEn8CLeBMPS0x1Q0xLNxZF@uyxLd5mdoZvJ5Pyuhb2gd2S5bduOkFmpb3hC101FYXk1EWL7OyzFYuTey8UF6S28jA1DDGG9oHCy8Nus/d7QYXZSD3kJ1IUVvVyRi97PbO1LctyrcdHor/Yq9TtK/FfDkPOIx8C9Y6BIowmYLxV@dyAxRCmgwL/4gSMH5jHVPn4GcMExHB3KVG8A8amc2@y1Q8 "C (gcc) – TIO Nexus")
[Answer]
# Python 2 or 3, ~~75~~ ~~73~~ 70 bytes
```
import re;f=lambda s:re.sub('(?i)(rex)|\w',lambda x:x.group(1)or'*',s)
```
Basically the same as my Ruby's [answer](https://codegolf.stackexchange.com/questions/119718/what-my-dog-really-hears/119755#119755).
-2 bytes thanks to @Wondercricket.
As a test:
```
tests = [
  ["Rex, I told you not to do this! You're making me angry Rex!", "Rex, * **** *** *** ** ** ****! ***'** ****** ** ***** Rex!"],
  ["Rex lives in Rexland.", "Rex ***** ** Rex****."],
  ["To call Rex, just say \"Rex\".", "** **** Rex, **** *** \"Rex\"."],
  ["My cat is getting anorexic.", "** *** ** ******* ***rex**."]
]
for test_in, test_out in tests:
    print(test_in)
    print(f(test_in))
    print(f(test_in) == test_out)
```
[Answer]
# Java 8, ~~187~~ ~~192~~ ~~168~~ ~~164~~ ~~159~~ 138 bytes
```
s->{for(int i=0;i<s.length();System.out.print(s.regionMatches(0<1,i,"rex",0,3)?s.substring(i,i+=3):s.replaceAll("\\w","*").charAt(i++)));}
```
-28 bytes thanks to @OlivierGrégoire.
**Explanation:**
[Try it online.](https://tio.run/##jZAxb8IwEIV3fsXJk12MRcXWQCt@AAylW9PBNSYcNU6UcygI5benlzRTp0r2cLbed@@9k73YWVn5eNp/dS5YIthYjPcJAMbk64N1Hrb9CHApcQ9O7lKNsQBSGb@2fPlQsgkdbCHCCjqaPd8PZS2ZALiaZ7gkE3ws0lGqbHej5M@mbJKpGJQkmdoXWMaNTe7oSc6Xjxq1qP1V6LleqBcy1HzSsFWixulqoZ56URXY3DoEKfL8W2jxIJRxR1uvk8TpVCmVtV02YXdV8xnY3WhyiHHmkGOS9w@w6jdhNE6KV3@FgBdP3ADwEGzcGzGkBfjrPkQ5/gzatxKcDaGXaTg1lIDsDfKemYv/QjY3hnBzBIVPqe/axpLrQDcS2knb/QA)
```
s->{                         // Method with String parameter and no return-type
  for(int i=0;i<s.length();  //  Loop over the characters of the input-String
    System.out.print         //   Print:
     s.regionMatches(1>0,i,"rex",0,3)? 
                             //    If we've found "rex" (case-insensitive):
      s.substring(i,i+=3)    //     Print this REX-word (case-sensitive)
     :                       //    Else:
      s.replaceAll("\\w","*").charAt(i++));
                             //     Print the current character,
                             //     or '*' if it's an alpha-numeric character
```
[Answer]
## Python 2, 87 Bytes
```
import re
print re.sub(r'(?i)[a-df-qs-wyz]|r(?!ex)|(?<!r)e|e(?!x)|(?<!re)x','*',input())
```
I guess that can be shortened? :)
[Answer]
# [sed](https://www.gnu.org/software/sed/), 37 33 bytes
36 bytes sourcecode + 1 byte for -r flag.
```
s:(rex)|\w:\1*:Ig
s:(rex)\*:\1:Ig
```
[Try it online!](https://tio.run/nexus/sed#LY7BCsIwEETv@YqxF7VowWv/oAcv4kXoJbShRtOsJFttwG83bsXLwHvLDpNjvQlm3r7bV90eyroZ1N@0pQjhnE9m3qEBk@uRaIInFkBP4KuNK1xoWgeDUd@tHzAaaD@EBHlbKQk4@zQR1i/Gad9X6kzotHP4Nd@myIg6oRAsKnVMcmTYiMEwL5XakyyyXfWhB1vyMe/DFw "sed – TIO Nexus")
[Answer]
# [QuadR](https://github.com/abrudz/QuadRS), ~~11~~ 10 + 1 = 11 bytes
+1 byte for the `i` flag.
```
rex
\w
&
*
```
[Try it online!](https://tio.run/##HY6xDsIwEEP3fIXbASSE8h8MLIgFieXUROUgzYnkAs3Xh5TF0rNly@9CLrWW/GruX7Mzh9Yufj3iBJXgUKUginaAE@iD84CblH3yWOjFccbiQXFOFb02mC4I/PEZHDcnUHTWXAUThYD/8rNkRaaKseNozbn2UMEZs1fdJilK/8OTbfwD "QuadR – Try It Online")
Explanation: Case-insensitively replace `rex` and word-chars with itself and asterisks, respectively.
[Answer]
# Gema, 25 characters
```
/[rR][eE][xX]/=$0
<L1>=\*
```
Sample run:
```
bash-4.3$ gema '/[rR][eE][xX]/=$0;<L1>=\*' <<< "Rex, I told you not to do this! You're making me angry Rex!
Rex lives in Rexland.
To call Rex, just say \"Rex\".
My cat is getting anorexic."
Rex, * **** *** *** ** ** ****! ***'** ****** ** ***** Rex!
Rex ***** ** Rex****.
** **** Rex, **** *** "Rex".
** *** ** ******* ***rex**.
```
Painful fact that could be `\CRex=$0;<L1>=\*`, but unfortunately `$0` contains the template, not the match. ☹
[Answer]
## PowerShell, 60 bytes
```
{$args|%{$_-replace'(rex)|\p{L}','$1*'-replace'(x)\*','$1'}}
```
[Try it online](https://tio.run/nexus/powershell#RY/BCsIwEETvfsVYoqulCn6AHyDoRbwIhRLbUKNpIkkqLW2/vaa9eFpmHjs7yx7HsWPclq5fdSzbWfFRPBe0saLZ9umnOw@UEDvE9EfNNo1nk4ZhjK6iSXCCN6pAa2po44NAYeCf0i1xNzVZgYq/pS5RCXBd2hZhbRklCwoTSn6Fg9STqbgu9hTAzSDnSmHOf9XOw/EW07lo5pc2cA/pUArvp2yuTWgt8z2FX9bsAZYN4w8)
[Answer]
# [Retina](https://github.com/m-ender/retina), ~~54~~ ~~50~~ 49 bytes
*Golfed 5 bytes thanks to @MartinEnder*
```
i(`[\w-[rex]]
*
(?<!r)e|e(?!x)|r(?!ex)|(?<!re)x
*
```
[Try it online!](https://tio.run/nexus/retina#HY7BCsIwEETv@YqpILai/QKhR/HgRbyIFhrapUbTBJJUE/Df67aXHeYts7Pr/NhMKm/uj@/@7ijWtdiKvDpkrqAf5VUWi59jIdYFUxHFdpouFHc4IVjdIdkRxgY26CzCU/kMNztuHGGQb2V6DARpepfAsUzwgFYf8lBmJlqarkTHlKK4WrRSaywFr9EHeJmwYrsqxTnxMkB59BTCfFkay1@rtvwD "Retina – TIO Nexus")
[Answer]
# [MATL](https://github.com/lmendo/MATL), 24 bytes
```
42y3Y2mFGk'rex'Xf!3:q+((
```
The input is a string enclosed in single quotes.
[Try it online!](https://tio.run/nexus/matl#@29iVGkcaZTr5p6tXpRaoR6RpmhsVaitofH/v3pQaoVCTmZZarFCZp4CkJOTmJeipxCSr5CcmJMDEtBRyCotLlEoTqxUUAJylfQUfCuBkiUKmcUKfv4hCumpJSWZeekKiXn5QLMzk/XUAQ "MATL – TIO Nexus")
### Explanation
Consider input `'Rex lives in Rexland.'`
```
42    % Push 42 (ASCII for '*')
      % STACK: 42
y     % Implicit input. Duplicate from below
      % STACK: 'Rex lives in Rexland.', 42, 'Rex lives in Rexland.'
3Y2   % Push string 'ABC...YZabc...yz'
      % STACK: 'Rex lives in Rexland.', 42, 'Rex lives in Rexland.', 'ABC...YZabc...yz'
m     % Ismember
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0]
F     % Push false
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0
Gk    % Push input lower-cased
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0, 'rex lives in rexland'
'rex' % Push this string
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0, 'rex lives in rexland', 'rex'
Xf!   % Strfind and transpose: gives indices of matchings as a column vector
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0, [1; 14]
3:q   % Push [0 1 2]
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0, [1; 14], [0 1 2]
+     % Addition, element-wise with broadcast
      % STACK: 'Rex lives in Rexland.', 42, [1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0], 0, [1 2 3; 14 15 16]
(     % Assignment indexing: sets indicated entries to 0
      % STACK: 'Rex lives in Rexland.', 42, [0 0 0 0 1 1 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0]
(     % Assignment indexing: sets indicated entries to 42 (that is, '*'). Implicit display
      % 'Rex ***** ** Rex****.'
```
[Answer]
# [Python 2](https://docs.python.org/2/), ~~93~~ 92 bytes
```
f=lambda s:s and("rex"==s[:3].lower()and s[:3]+f(s[3:])or("*"+s)[s[0].isalpha()<1]+f(s[1:]))
```
[Try it online!](https://tio.run/nexus/python2#Jc1BCsMgEEDRqwyuZhqQhuykHqEnEBc20VSwGhwh7emttNvPg9@DTu712BywYnB5Q1H9W2jNRi1WpnL6ijQ6/MIUkM2iLJWK4iImJsPmamVkl46nQ7rNfzMPQ/2oMTcIKO4fWF2DyLD71mLex6qMUVyloP4F "Python 2 – TIO Nexus")
[Answer]
# Perl, 31 bytes
```
s/(rex)|[a-z]/$1||"*"/ieg;print
```
Invoke perl with `-n` option. For example:
```
echo 'To call rex, just say "Rex".'| perl -ne 's/(rex)|[a-z]/$1||"*"/ieg;print'
** **** rex, **** *** "Rex".
```
[Answer]
# [Bash](https://www.gnu.org/software/bash/), 128 bytes
```
r=REXrex;a=`tr -c $r'",. !
' l<<<$1`;for i in {r,R}{e,E}{x,X};{
a=`echo ${a[@]//$i/$(tr $r f-k<<<$i)}`;}
tr $r l<<<$a|tr f-l $r*
```
[Try it online!](https://tio.run/nexus/bash#JYxBC4IwGIbv/orXGFgxk84qdOnQ1VMRgUNXjnSDrwXG2s/ubLOO7/PyPBOV1f5IcsxFWVtC2oBRsuAbxFGCvigKtq3zqyEoKA1HvPJO8r13Iz/63EVBk01nwJw47y5ZxlTGliHECNf0Pvtq5evcR3/2K4q3nd8@gPU0TZUcOQ6wpm/xMk9oY8NAa2A79YhxMs@EJAZxV/qGQULoG70QtPijTdqIppNf "Bash – TIO Nexus")
I'm sticking to tr on my previous answer, non-functional bash array string replace and no preg replace!
Less golfed:
```
    a=`echo $1 |tr -c 'REXrex.,\"! ' 'z'`;        -> a replaces with z chars in input not matching REXrex or punctuation
    for i in {r,R}{e,E}{x,X}; {                   -> iterates over rex .. rEx .. REX
      j=$(tr 'REXrex' 'ABCabc' <<<$i)}            -> holds a for r, A for R, ando so on
      a=`echo ${a[@]//$i/$j`;                     -> replace each combination of rex .. rEx .. REX with abc ... aBc.. ABC
    }
    tr 'REXrex' 'z' <<<$a |tr 'ABCabcz' 'REXrex*' -> replaces each remainig r,e,x,R,E,X with z and finally each ABC with REX and z with *
```
Had to use z instead of \* because of expansion
[Answer]
## C#, ~~93~~ 90 bytes
```
s=>System.Text.RegularExpressions.Regex.Replace(s,"(?i)rex|\w",m=>m.Length>1?m.Value:"*");
```
Believe this is the first time I've used a regex in a C# answer here because of the long namespace `System.Text.RegularExpressions`.
---
Didn't realise it when I wrote my answer but this seems to be the C# version of [@Shaggy's JavaScript answer](https://codegolf.stackexchange.com/a/119742/38550).
[Answer]
# [CJam](https://sourceforge.net/p/cjam), 39 bytes
```
q{_3<_el"rex"=3{elc_'{,97>&'*@?1}?\o>}h
```
[Try it online!](https://tio.run/nexus/cjam#@19YHW9sE5@ao1SUWqFka1ydmpMcr16tY2lup6au5WBvWGsfk29Xm/H/f1BqhY6Cp0JJfk6KQmV@qUJefgmQo5CSr1CSkVmsqBCZX6pelKqQm5idmZeukJuqkJiXXlSpANSmCAA "CJam – TIO Nexus")
**How it works**
```
q           e# Read the input.
{           e# Do:
 _3<        e#  Copy the string and get its first three characters.
 _el"rex"=  e#  Check case-insensitively if they equal "rex".
  3         e#   If they do, push 3.
  {         e#   If they don't:
   elc_     e#    Take the first character of the three, and make it lowercase.
   '{,97>&  e#    Take its set intersection with the lowercase alphabet. Returns a non-empty
            e#      string (truthy) if it's a letter or an empty string (falsy) if not.
   '*@?     e#    Push a * if the char is a letter, or itself if it's not.
   1        e#    Push 1.
  }?        e#  (end if)
 \o         e#  Print the second-from-the-top stack item.
 >          e#  Slice the string after the first 3 or 1 characters, depending on previous outcome.
}h          e# Repeat the above until the string is empty.
```
[Answer]
# VimScript, 34 bytes
```
s/\v(rex|r@<=ex|(re)@<=x)@!\w/*/gi
```
And here's an interesting substitution that almost works:
```
s/\vr(ex)@!|<e|<x|[rex]@!\w/*/gi
```
Imagine running this repeatedly on the string `Rex, dex, I told you not to do this! You're making me angry Rex!` After the first line, the string is `Rex, *ex, * **** *** *** ** ** ****! ***'*e ****** *e ***** Rex!` The second pass will result in `Rex, **x, * **** *** *** ** ** ****! ***'** ****** ** ***** Rex!`, and the third pass will finish it. Any subsequent passes will not change the string. However, it could take more than 3 substitutions to get there, for example on string `xxxxxxxx`. So, if there were an easy way to run the above substitution until it stopped changing things, or as many times as the length of the input, that would be another solution. I bet it could be done in V, but it would still probably be longer than 34 bytes.
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 23 [bytes](https://github.com/DennisMitchell/jelly/wiki/CodePage)
*No response in over 24 hours to [my question regarding case](https://codegolf.stackexchange.com/questions/119718/what-my-dog-really-hears?answertab=votes#comment293505_119718), so I'll post this tentative 23 byter.*
```
“rex”
Œlœṣ¢µØaW;”*yµ€j¢
```
See the test cases at **[Try it online!](https://tio.run/nexus/jelly#@/@oYU5RasWjhrlcRyflHJ38cOfiQ4sObT08IzHcGiioVXlo66OmNVmHFv0/uudwO5AZCeI@atz@cMeSQ0v@/49WD0qtUMjJLEstVsjMUwBychLzUvTUdRTUQ/IVkhNzckBiOgpZpcUlCsWJlQpKQK4SWN63EihfopBZrJCeWlKSmZeukJiXD3RLZrKeeiwA)**
### How?
```
“rex” - Link 1, get "rex": no arguments
“rex” - literal "rex"
Œlœṣ¢µØaW;”*yµ€j¢ - Main link: string s (or list of characters)
Œl                - convert s to lowercase
    ¢             - call the last link (1) as a nilad (get "rex")
  œṣ              - split left (s) at sublists equal to right ("rex")
     µ            - call the result t
             µ€   - for each word, w, in t:
      Øa          -   literal: lowercase alphabet
        W         -   wrap it in a list
          ”*      -   literal: '*'
         ;        -   concatenate the wrapped alphabet with the asterisk
            y     -   translate: replace all lowercase letters with asterisks.
                ¢ - call the last link (1) as a nilad (get "rex")
               j  - join left (translated, split text) with copies of right ("rex")
```
[Answer]
# [CJam](https://sourceforge.net/p/cjam), 26 bytes (uppercase output) / 36 bytes (case-preserving)
```
qeu"REX":R/{__el-'*@?}f%R*
```
[Try it online!](https://tio.run/nexus/cjam#@1@YWqoU5BqhZBWkXx0fn5qjq67lYF@bphqk9f9/UGqFjoKnQkl@TopCZX6pQl5@CZCjkJKvUJKRWayoEJlfql6UqpCbmJ2Zl66Qm6qQmJdeVKkA1KYIAA "CJam – TIO Nexus")
If letter case needs to be preserved (since [that's still a little bit unclear](https://codegolf.stackexchange.com/questions/119718/what-my-dog-really-hears#comment293505_119718)), that can be accomplished with 10 extra bytes:
```
q_32f&:i\eu"REX":R/{__el-'*@?}f%R*.|
```
[Try it online!](https://tio.run/nexus/cjam#@18Yb2yUpmaVGZNaqhTkGqFkFaRfHR@fmqOrruVgX5umGqSlV/P/f1BqhY6Cp0JJfk6KQmV@qUJefgmQo5CSr1CSkVmsqBCZX6pelKqQm5idmZeukJuqkJiXXlSpANSmCAA "CJam – TIO Nexus")
By the way, while writing this answer, I found what I would consider to be a design bug in CJam: the bitwise operators `&` and `|` are not defined between two char values, so I can't use `.|` to take the bitwise OR of two strings. The solution, which ended up costing me two extra bytes, is to first convert one of the strings with `:i` into an array of integers, which then can be ORed with the other string. (Actually it cost me *three* bytes, because if `&` worked between two chars, I could've also used `Sf&` instead of `32f&` to save the letter case information.)
On the positive side, I did discover that `{...}f%` indeed works as expected for iterating over the characters in an array of strings. Nice.
Anyway, here's a (lightly) commented version of the 36-byte code:
```
q                                       "read input";
 _32f&:i\                               "save the case bit of each input char";
         eu"REX":R/                     "uppercase input and split it on 'REX'";
                   {                    "start code block:"
                    __el-'*@?           "c = (c != lowercase(c) ? '*' : c)";
                             }f%        "apply block to chars in each substring";
                                R*      "join the substrings with 'REX' again";
                                  .|    "bitwise OR the case bits back in";
```
The case-saving trick works because the case of ASCII letters is solely determined by the fifth bit of the ASCII code: this bit is 0 for uppercase and 1 for lowercase letters. Thus, taking the bitwise AND of the character code with 32 = 25 extracts the case bit, and bitwise ORing this bit with the uppercased letters restores their original case.
Of course, non-alphabetic characters may have arbitrary values for the fifth bit (although, due to the way ASCII characters are organized, most punctuation characters have the fifth bit set to 1) but this doesn't matter, since those characters are left untouched by uppercasing and the letter censoring loop anyway, and ORing a character with its own fifth bit does't change it. Also, conveniently, the `*` character already has the fifth bit set, so it is also left unchanged by the final `.|`.
[Answer]
# Java 7, ~~96~~ ~~98~~ ~~97~~ 96 bytes
+2 bytes for missing e's preceded by r or followed by x but not both
-1 byte for changing `[a-z&&[^rex]]` to `(?![rex])\\w`
```
String a(String s){return s.replaceAll("(?i)r(?!ex)|(?<!r)e|e(?!x)|(?<!re)x|(?![rex])\\w","*");}
```
[Try it online!](https://tio.run/nexus/java-openjdk#hY8xbsMwDEXn9BS0JqkIfIG0MHqALEm3OAOrEIYKWTZEOrHR@Owuk6ZrO5Gf5Pvg9xGZYYshwdfTqh8@YvDAgqLl3IUTtLqye8khNYcjYG7Y6eHqTrSvkOhyp63b6HQ/sVBbdoOUvRISk21LtGZHI8RwJgalVERMp9K4P5n3DjzGeDtfw@fAAowT1Dev2vwHbyeFBQJDQyL6O2DqMo3BP8h5@ckE@AgHmiuTDDkBl5n6iJ7eYrTGVsFlWxU0uqutXors6EqqfyW5UZvioO5HV9cXszbPxm3mZV6@AQ)
A regex version for replacing using Java
Replaces everything in this regex with a \* (note in Java \w has to be escaped as \\w)
```
(?i)r(?!ex)|(?<!r)e|e(?!x)|(?<!re)x|(?![rex])\w
(?i)                                                   // Case Insensitive
    r(?!ex)                                            // Any r not followed by ex
           |(?<!r)e                                    // Or any e not preceded by r
                   |e(?!x)                             // Or any e not followed by x
                          |(?<!re)x                    // Or any x not preceded by re
                                   |(?![rex])\w        // Or any other word character
```
[Answer]
# [Pip](https://github.com/dloscutoff/pip), ~~21~~ 19 bytes
```
qR-`(rex)|\w`{b|'*}
```
Takes input from stdin, outputs to stdout. [Try it online!](https://tio.run/##K8gs@P@/MEg3QaMotUKzJqY8oTqpRl2r9v//oNQKhZzMstRihcw8BSAnJzEvRe8/AA "Pip – Try It Online")
### Explanation
```
q                    Read a line of stdin
 R                   and replace
   `(rex)|\w`          a regex matching `rex` or any single alphanumeric character,
  -                    case-insensitive
             {    }  with this callback function:
              b|'*     If the 1st capture group (rex) matched, return it, else asterisk
                       The result of the replacement is auto-printed
```
[Answer]
# [V](https://github.com/DJMcMayhem/V), ~~27~~, 24 bytes
I'm leaving both answers up, because I think they're equally interesting.
# 27 bytes
```
òÓãr¨ex©À!ü¼eü¼xü[rex]À!÷/*
```
[Try it online!](https://tio.run/##K/v///Cmw5MPLy46tCK14tDKww2Kh/cc2pMKIioO74kuSq2IBYlt19f6/z8otUJHIQVEeCqU5OekKFTmlyrk5ZcAOQop@QolGZnFigqR@aXqRakKuYnZmXnpCrmpCol56UWVCkC9igA "V – Try It Online")
Thanks to Brian McCutchon for his idea to [do this in V](https://codegolf.stackexchange.com/a/119887/31716)
Hexdump:
```
00000000: f2d3 e372 a865 78a9 c021 fcbc 65fc bc78  ...r.ex..!..e..x
00000010: fc5b 7265 785d c021 f72f 2a              .[rex].!./*
```
Explanation:
```
ò                           " Until the output stops changing...
 Óãr¨ex©À!ü¼eü¼xü[rex]À!÷/* " Run the compressed vim regex:
:s/\vr(ex)@!|<e|<x|[rex]@!\w/*/gi
```
# 24 bytes
```
Óãrex/ò&ò
HòÓ÷/*/e
jjòÍî
```
[Try it online!](https://tio.run/##K/v///Dkw4uLUiv0D29SO7yJy@PwJqDAdn0t/VSurCwgp/fwuv//g1IrdBRSQISnQkl@TopCZX6pQl5@CZCjkJKvUJKRWayoEJlfql6UqpCbmJ2Zl66Qm6qQmJdeVKkA1KsIAA "V – Try It Online")
```
Ó           " Substitute
 ã          "   (case-insensitive)
  rex       "   'rex'
     /      " with
       &    "   'rex'
      ò ò   "   Surrounded in new lines
ò           " Recursively...
 Ó          "   Substitute...
  ÷         "     A word character
   /        "   with
    *       "     An asterisk
     /e     "     (don't break if there are 0 matches)
jj          "   Move down 2 lines
  ò         " end the recursive loop
   Íî       " Remove all newlines
```
]