86
\$\begingroup\$

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**.

\$\endgroup\$
24
  • 30
    \$\begingroup\$ Test case: Hello! Isn't this ... a nice challenge? Can you dog hear *****! ***'* *** ... * **** *********?? If so, you might consider communicating in morse from now on... \$\endgroup\$ May 9, 2017 at 9:16
  • 2
    \$\begingroup\$ Do we only need to support a-zA-Z, or also 0-9 and/or äëïöüÿãõñáéíóúýàèìòùç etc. etc.? And could you add some test cases regarding these? \$\endgroup\$ May 9, 2017 at 9:20
  • 2
    \$\begingroup\$ @KevinCruijssen Since $0-9$ or accented characters are not mentioned in the initial challenge, do not consider them as part of the challenge. \$\endgroup\$ May 9, 2017 at 9:23
  • 7
    \$\begingroup\$ Since "dogs don't get the difference between lowercase and uppercase", may the output case be different to the input? (For example: input="Rex lives in Rexland.", output="rex ***** ** rex****."; or alternatively input="My cat is getting anorexic.", output="** *** ** ******* ***Rex**.") \$\endgroup\$ May 9, 2017 at 16:02
  • 6
    \$\begingroup\$ Why did this challenge use asterisks instead of "blah"s??? \$\endgroup\$
    – hBy2Py
    May 11, 2017 at 19:44

40 Answers 40

164
\$\begingroup\$

**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

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

  1. overlay simply overlays the string1 on top of string2 at the specified position.

See here for overlay function

\$\endgroup\$
3
  • 55
    \$\begingroup\$ ... but the dog thought he programmed it in REX*. \$\endgroup\$ May 9, 2017 at 13:24
  • 11
    \$\begingroup\$ How many of these upvotes are purely for the choice of language?! :D \$\endgroup\$
    – Shaggy
    May 9, 2017 at 15:05
  • 75
    \$\begingroup\$ @Shaggy At least all of them \$\endgroup\$ May 9, 2017 at 15:39
26
\$\begingroup\$

Retina, 24 21 bytes

i`(rex)|(\w)
$1$#2$**

Try it online!

Explanation

Skipping rexs 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.
\$\endgroup\$
2
  • \$\begingroup\$ Doesn't retina have \a for [a-z] z.B.? \$\endgroup\$
    – Leaky Nun
    May 9, 2017 at 12:44
  • \$\begingroup\$ @LeakyNun no. I'd have to tokenise the regex (or even implement my own flavour) to add any features to the regex flavour itself. \$\endgroup\$ May 9, 2017 at 12:45
24
\$\begingroup\$

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 "*".
\$\endgroup\$
2
13
\$\begingroup\$

APL (Dyalog Unicode), 22 bytesSBCS

'rex' '\w'⎕R'\0' '*'⍠1

Try it online!

Simple PCRE Replace.

⍠1 sets case insensitivity. Simply replaces rex with itself and all other word characters with asterisks.

\$\endgroup\$
5
  • \$\begingroup\$ \w includes the underscore character, assuming this is RegEx - I don't know APL. \$\endgroup\$
    – Shaggy
    May 9, 2017 at 22:10
  • \$\begingroup\$ @Shaggy Yeah, Dyalog APL uses PCRE, but it is not certain from OP that underscores will occur. E.g. digits will not. \$\endgroup\$
    – Adám
    May 9, 2017 at 22:13
  • \$\begingroup\$ Do we not have to assume they can occur, unless told otherwise? \$\endgroup\$
    – Shaggy
    May 9, 2017 at 22:15
  • \$\begingroup\$ @Shaggy Normally, yes, but this seems to indicate that what isn't mentioned will not occur. OP only mentions comma, period, space, and exclamation point. \$\endgroup\$
    – Adám
    May 9, 2017 at 22:17
  • \$\begingroup\$ Hmm ... I think I'll wait for confirmation that they won't occur, seeing as I've left that comment about \w on a few answers now! \$\endgroup\$
    – Shaggy
    May 10, 2017 at 8:41
11
\$\begingroup\$

Perl 5, 24 bytes

23 bytes of code + -p flag.

I used Martin Ender's regex from his Retina answer (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!

\$\endgroup\$
8
\$\begingroup\$

Retina, 32 31 bytes

iS`(rex)
%iT`Ll`*`^(?!rex).*
¶

Try it online! 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.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ This is at least the second time that I'm thinking transliteration mode could use an option to transliterate the non-matches... \$\endgroup\$ May 9, 2017 at 9:49
  • \$\begingroup\$ @MartinEnder too late :-D \$\endgroup\$ May 9, 2017 at 13:50
8
\$\begingroup\$

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 (with the replacement function).

The output is stored in the first parameter which is an in/out parameter.

Thanks to Johan du Toit for letting me know that recursion is slightly shorter.

\$\endgroup\$
3
  • \$\begingroup\$ There exists a C environment that provided strncmpi so you can get it in 69. I've got it on CD. \$\endgroup\$
    – Joshua
    May 10, 2017 at 20:52
  • 1
    \$\begingroup\$ @Joshua Thanks. What is CD? \$\endgroup\$
    – 2501
    May 10, 2017 at 20:56
  • \$\begingroup\$ Borland C++ 4.5 \$\endgroup\$
    – Joshua
    May 10, 2017 at 21:14
7
\$\begingroup\$

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."
\$\endgroup\$
0
6
\$\begingroup\$

PHP, 78 Bytes

<?=preg_replace("#[a-df-qs-wyz]|r(?!ex)|(?<!r)e|e(?!x)|(?<!re)x#i","*",$argn);

Try it online!

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!

\$\endgroup\$
4
  • \$\begingroup\$ You can use \w instead of \pL. \$\endgroup\$
    – Adám
    May 11, 2017 at 14:07
  • \$\begingroup\$ @Adám Thank you it makes my longer approach only 1 Byte shorter and not really clearer what should make in case of underscore or number \$\endgroup\$ May 11, 2017 at 14:20
  • \$\begingroup\$ The input will never have any underscores or numbers.. \$\endgroup\$
    – Adám
    May 11, 2017 at 14:23
  • \$\begingroup\$ @Adám I have make an extra point for it and have edit the longer approach why I have found an other improvement \$\endgroup\$ May 11, 2017 at 14:50
5
\$\begingroup\$

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!

\$\endgroup\$
4
  • \$\begingroup\$ f(char*s){for(;*s;s++)strncasecmp("Rex",s,3)?putchar(isalpha(*s)?42:*s):write(1,s-2,3,s+=2);}. What kind of sorcery is f(s)char*s;{}? I've never seen this syntax before. \$\endgroup\$
    – Christoph
    May 9, 2017 at 10:35
  • \$\begingroup\$ Oh, it used to have another parameter but i forgot to remove that. \$\endgroup\$
    – betseg
    May 9, 2017 at 11:13
  • \$\begingroup\$ Doesn't work correctly, because only the first call to the function works. See here: tio.run/nexus/… Solutions in function form, such as this one, must be able to be called again and produce correct results. \$\endgroup\$
    – 2501
    May 9, 2017 at 18:26
  • \$\begingroup\$ @2501 thanks, fixed. \$\endgroup\$
    – betseg
    May 9, 2017 at 18:49
5
\$\begingroup\$

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.

-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)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You could save 2 bytes by removing the spacing between x.group(1) or '*' \$\endgroup\$ May 9, 2017 at 15:25
  • \$\begingroup\$ @Wondercricket: Thank you very much, it's my first golf answer in Python. \$\endgroup\$ May 9, 2017 at 16:16
5
\$\begingroup\$

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.

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
\$\endgroup\$
5
  • \$\begingroup\$ @Shaggy Should be fixed now. This was posted before it was specified in the comments that 0-9 and accented characters shouldn't be included, only a-zA-Z should. \$\endgroup\$ May 9, 2017 at 14:35
  • \$\begingroup\$ Could you replace "[a-zA-z]" with /[a-z]/i? \$\endgroup\$
    – Shaggy
    May 9, 2017 at 14:38
  • \$\begingroup\$ @Shaggy Yes/no. Java uses a slightly different regex syntax than python or C# for example. So yes, it is possible to use a case-insensitive regex, but it will be one byte longer: "[a-zA-Z]" -> "(?i)[a-z]". \$\endgroup\$ May 9, 2017 at 14:43
  • 1
    \$\begingroup\$ I think you should use s.regionMatches(0<1,i,"rex",0,3) instead of s.toLowerCase().substring(i,i+(i>l-3?1:3)).equals("rex"). \$\endgroup\$ May 9, 2017 at 14:44
  • 1
    \$\begingroup\$ @KevinCruijssen Take the current code that you have (at 168 bytes), remove the variable l and save 4 bytes. \$\endgroup\$ May 9, 2017 at 19:39
4
\$\begingroup\$

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? :)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You can get rid of the spaces after the commas between arguments for 2 bytes off. \$\endgroup\$
    – user45941
    May 9, 2017 at 11:34
4
\$\begingroup\$

sed, 37 33 bytes

36 bytes sourcecode + 1 byte for -r flag.

s:(rex)|\w:\1*:Ig
s:(rex)\*:\1:Ig

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ @Shaggy Thanks for the heads up! \$\endgroup\$ May 11, 2017 at 14:01
  • \$\begingroup\$ You use use . instead of \* \$\endgroup\$
    – user41805
    Aug 28, 2019 at 5:39
4
\$\begingroup\$

QuadR, 11 10 + 1 = 11 bytes

+1 byte for the i flag.

rex
\w
&
*

Try it online!

Explanation: Case-insensitively replace rex and word-chars with itself and asterisks, respectively.

\$\endgroup\$
3
\$\begingroup\$

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. ☹

\$\endgroup\$
3
\$\begingroup\$

PowerShell, 60 bytes

{$args|%{$_-replace'(rex)|\p{L}','$1*'-replace'(x)\*','$1'}}

Try it online

\$\endgroup\$
6
  • \$\begingroup\$ My fault. I've replace \w to \p{L}. \$\endgroup\$ May 9, 2017 at 13:22
  • \$\begingroup\$ Interesting idea. Note that using $args as an array has consequences when things are quoted, as in one example. And if you're only using the first argument anyway, you don't need the foreach. \$\endgroup\$
    – Joey
    May 10, 2017 at 17:02
  • \$\begingroup\$ @AndreiOdegov You can go back to \w. Side note: Are the braces in \p{L} really needed? \$\endgroup\$
    – Adám
    May 11, 2017 at 14:06
  • 1
    \$\begingroup\$ very nice Regex, "$args"-replace'(rex)|\p{L}','$1*'-replace'(x)\*','$1' is much shorter overall, wrapping $args in quotes turns it all into a single string and saves you a lot. \$\endgroup\$
    – colsw
    May 11, 2017 at 15:39
  • \$\begingroup\$ @Adám The curly braces in .NET is required. \$\endgroup\$ May 11, 2017 at 17:35
3
\$\begingroup\$

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!

\$\endgroup\$
5
  • \$\begingroup\$ @Emigna Just realised that my solution does not work for dex, it gives *e* while yours gives **x. \$\endgroup\$
    – user41805
    May 9, 2017 at 9:21
  • \$\begingroup\$ If you group both stages by putting ( after the first i you don't need to configure the second stage. \$\endgroup\$ May 9, 2017 at 11:44
  • \$\begingroup\$ And your first regex can be written as [a-z-[rex]]. \$\endgroup\$ May 9, 2017 at 11:46
  • \$\begingroup\$ @MartinEnder Thanks, this is the first time I'm seeing character classes where you can exclude certain characters \$\endgroup\$
    – user41805
    May 10, 2017 at 15:49
  • \$\begingroup\$ they exist in several flavours but I believe .NET's syntax for them is unique. \$\endgroup\$ May 10, 2017 at 17:09
2
\$\begingroup\$

MATL, 24 bytes

42y3Y2mFGk'rex'Xf!3:q+((

The input is a string enclosed in single quotes.

Try it online!

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****.'
\$\endgroup\$
2
\$\begingroup\$

Python 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!

\$\endgroup\$
2
\$\begingroup\$

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".
\$\endgroup\$
2
  • \$\begingroup\$ [a-z] can now be replaced with \w as the input will never contain numbers or underscores. \$\endgroup\$
    – Shaggy
    May 11, 2017 at 13:59
  • \$\begingroup\$ You can use -p instead of -n and remove ;print \$\endgroup\$
    – wastl
    Mar 14, 2018 at 16:12
2
\$\begingroup\$

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!

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

\$\endgroup\$
6
  • 2
    \$\begingroup\$ looks its not the right tool :P \$\endgroup\$
    – marcosm
    May 9, 2017 at 15:07
  • 1
    \$\begingroup\$ You can save a couple of characters by not quoting tr's parameters when they contain nothing expandable. \$\endgroup\$
    – manatwork
    May 9, 2017 at 15:46
  • \$\begingroup\$ In regards to your other bash answer: Feel free to fix, and then flag for mod attention requesting undeletion. \$\endgroup\$
    – Riker
    May 9, 2017 at 17:53
  • 1
    \$\begingroup\$ Looking again, there are quite many rexes for a r=REXrex variable to worth. \$\endgroup\$
    – manatwork
    May 10, 2017 at 11:20
  • \$\begingroup\$ If you keep $r out of quoted string, you not need to change the surrounding ' to ", so no need to escape the literal ". Of course, then you write a literal newline by breaking the line in that place instead of \n: $r'",. !␤'. \$\endgroup\$
    – manatwork
    May 10, 2017 at 12:14
2
\$\begingroup\$

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.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thanks for the mention, even though you came up with your answer independently of mine. \$\endgroup\$
    – Shaggy
    May 9, 2017 at 17:26
  • \$\begingroup\$ @Shaggy Ah thanks didn't know it had been updated \$\endgroup\$ May 11, 2017 at 20:37
1
\$\begingroup\$

CJam, 39 bytes

q{_3<_el"rex"=3{elc_'{,97>&'*@?1}?\o>}h

Try it online!

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.
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the idea! Here's a V answer. :) \$\endgroup\$
    – DJMcMayhem
    Jan 5, 2018 at 0:25
1
\$\begingroup\$

Jelly, 23 bytes

No response in over 24 hours to my question regarding case, so I'll post this tentative 23 byter.

“rex”
Œlœṣ¢µØaW;”*yµ€j¢

See the test cases at Try it online!

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")
\$\endgroup\$
3
  • \$\begingroup\$ I'm not sure this is valid. It doesn't match the test cases. \$\endgroup\$
    – Okx
    May 10, 2017 at 19:24
  • \$\begingroup\$ See my note right at the top, and my question to OP. \$\endgroup\$ May 10, 2017 at 19:25
  • \$\begingroup\$ ( although unfortunately the comment I linked to where the OP said "dogs don't get the difference between lowercase and uppercase" has now gone) \$\endgroup\$ May 10, 2017 at 19:27
1
\$\begingroup\$

CJam, 26 bytes (uppercase output) / 36 bytes (case-preserving)

qeu"REX":R/{__el-'*@?}f%R*

Try it online!

If letter case needs to be preserved (since that's still a little bit unclear), that can be accomplished with 10 extra bytes:

q_32f&:i\eu"REX":R/{__el-'*@?}f%R*.|

Try it online!

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 .|.

\$\endgroup\$
1
\$\begingroup\$

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!

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
\$\endgroup\$
0
1
\$\begingroup\$

Pip, 21 19 bytes

qR-`(rex)|\w`{b|'*}

Takes input from stdin, outputs to stdout. 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
\$\endgroup\$
1
\$\begingroup\$

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!

Thanks to Brian McCutchon for his idea to do this in V

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!

Ó           " 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
\$\endgroup\$

Your Answer

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

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