Common words should still be avoided to be used as passwords. This challenge is about coding a very simple program that munges a given password (Modify Until Not Guessed Easily).


A word, which is a string written in the alphabet abcdefghijklmnopqrstuvwxyz. It does not matter if the letters are lowercase or uppercase.


  1. Change any repeated sequence of a same letter to itself preceded by the number of times the letter was repeated (LLLL with 4L)
  2. Change the first a with @
  3. Change the first b with 8
  4. Change the first c with (
  5. Change the first d with 6
  6. Change the first e with 3
  7. Change the first f with #
  8. Change the first g with 9
  9. Change the first h with #
  10. Change the first i with 1
  11. Change the second i with !
  12. Change the first k with <
  13. Change the first l with 1
  14. Change the second l with i
  15. Change the first o with 0
  16. Change the first q with 9
  17. Change the first s with 5
  18. Change the second s with $
  19. Change the first t with +
  20. Change the first v with >
  21. Change the second v with <
  22. Change the first w with uu
  23. Change the second w with 2u
  24. Change the first x with %
  25. Change the first y with ?

Rule 1 must be applied the needed number of times until it is not possible to apply it more. After that the rest of the rules are applied.

Output The munged word


  • codegolf --> (0639o1#
  • programming --> pr09r@2m1ng
  • puzzles --> pu2z135
  • passwords --> p@25uu0r6$
  • wwww --> 4uu
  • aaaaaaaaaaa --> 11a
  • lllolllolll --> 3103io3l
  • jjjmjjjj --> 3jm4j

This is , so please make your program as short as possible!

Nothing in this post should be used as password ideas or as any part of password practices.

  • 18
    \$\begingroup\$ The very fact that programs like this are possible means that the attacker could write them and munge the password (and try the various munges) just as easily (even easier because they often have access to better hardware). So just for safety's sake I will say: nothing in this post should be used as password ideas or as any part of password practices. \$\endgroup\$ – NH. Oct 19 '17 at 16:41
  • 1
    \$\begingroup\$ I recommend making that disclaimer bold and duplicating it at the top. You can never be too careful... \$\endgroup\$ – wizzwizz4 Oct 21 '17 at 13:57

14 Answers 14


Java 8, 237 321 319 280 247 241 240 237 bytes

s->{for(int a[]=new int[26],i=0,l=s.length,t,x;i<l;i+=t){for(t=0;++t+i<l&&s[i]==s[t+i];);System.out.print((t>1?t+"":"")+(++a[x=s[i]-65]>2?s[i]:"@8(63#9#1J<1MN0P9R5+U>u%?ZABCDEFGH!JKiMNOPQR$TU<2XYZ".charAt(x+26*~-a[x])+(x==22?"u":"")));}}

+84 bytes because the rules got changes.. (EDIT: Finally back to my initial 237 bytes.) Replacing WWWW with 222W is easy in Java, but with 4W not.. If only Java had a way to use the regex capture-group for something.. Getting the length with "$1".length(), replacing the match itself with "$1".replace(...), converting the match to an integer with new Integer("$1"), or using something similar as Retina (i.e. s.replaceAll("(?=(.)\\1)(\\1)+","$#2$1")) or JavaScript (i.e. s.replaceAll("(.)\\1+",m->m.length()+m.charAt(0))) would be my number 1 thing I'd like to see in Java in the future to benefit codegolfing.. >.> I think this is the 10th+ time I hate Java can't do anything with the capture-group match..
-78 bytes thanks to @OlivierGrégoire.

I/O is uppercase.


Try it here.

s->{                           // Method with String parameter and no return-type
  for(int a[]=new int[26],     //  Array with 26x 0
          i=0,                 //  Index-integer, starting at 0
          l=s.length,          //  Length
          t,x;                 //  Temp integers
      i<l;                     //  Loop (1) over the characters of the input
      i+=t){                   //    After every iteration: Increase `i` by `t`
    for(t=0;++                 //   Reset `t` to 1
        t+i<l                  //   Inner loop (2) from `t+i` to `l` (exclusive)
        &&s[i]==s[t+i];        //   as long as the `i`'th and `t+i`'th characters are equal
    );                         //   End of inner loop (2)
    System.out.print(          //   Print:
     (t>1?t+"":"")             //    If `t` is larger than 1: print `t`
     +(++a[x=s[i]-65]>2?       //    +If the current character occurs for the third time:
       s[i]                    //      Simply print the character
      :                        //     Else:
                               //      Print the converted character at position `x`
        +26*~-a[x])            //       + 26 if it's the second time occurring
       +(x==22?"u":"")));      //      And also print an additional "u" if it's 'W'
  }                            //  End of loop (1)
}                              // End of method

JavaScript (ES6), 147 bytes


Test Cases




Runs through a series of replacements on the input string, s, in the order specified by the challenge. Each item in the series is an array or string, with two items, that is then spread (...r) and passed to s.replace().

    [/(.)\1+/g, m=>m.length + m[0]],// first replacement: transform repeated letters
                                    // into run-length encoding

                                    // string split into length-2 partitions and
                                    // spread into the main array
                                    // next replacements: all single-char replacements.
                                    // "second" versions are placed at the end so they
                                    //    replace the second instance of that char

    ["w","uu"],["w","2u"]           // last replacements: the two "w" replacements
.map(r=> s = s.replace(...r))       // run all replacements, updating s as we go
&& s                                // and return the final string
  • \$\begingroup\$ Very good answer \$\endgroup\$ – mdahmoune Oct 19 '17 at 15:36

05AB1E, 69 bytes

-9 bytes thanks to Emigna


Try it online!

  • \$\begingroup\$ You could use 'w„uu„2u‚â \$\endgroup\$ – Emigna Oct 19 '17 at 14:37
  • \$\begingroup\$ Plz could you verify result for wwww as input? \$\endgroup\$ – mdahmoune Oct 19 '17 at 14:38
  • \$\begingroup\$ @mdahmoune It outputs 4uu \$\endgroup\$ – Okx Oct 19 '17 at 14:38
  • \$\begingroup\$ @Emigna Cartesian product, good idea. \$\endgroup\$ – Okx Oct 19 '17 at 14:39
  • \$\begingroup\$ First part can be γvygD≠×yÙ}J \$\endgroup\$ – Emigna Oct 19 '17 at 14:44

Perl 5, 152 + 1 (-p) = 153 bytes

s/(.)\1+/(length$&).$1/ge;%k='a@b8c(d6e3f#g9h#i1j!k<l1mio0q9r5s$t+u>v<x%y?'=~/./g;for$i(sort keys%k){$r=$k{$i};$i=~y/jmru/ilsv/;s/$i/$r/}s/w/uu/;s/w/2u/

Try it online!

  • \$\begingroup\$ Plz what do you mean by (-p)? \$\endgroup\$ – mdahmoune Oct 19 '17 at 16:03
  • 1
    \$\begingroup\$ @mdahmoune -p is used as an argument to perl at the commandline that automatically reads input from STDIN and prints the contents of $_ at the end of the script. TIO allows that option, and since perl -pe<code> is 1 more byte than perl -e<code> it's counted as one additional byte. \$\endgroup\$ – Dom Hastings Oct 19 '17 at 17:15
  • \$\begingroup\$ I think you've made a typo, shouldn't the ~ between j~k be an ! instead? Currently it replaced the second occurrence of i with a ~ instead of a !. \$\endgroup\$ – Kevin Cruijssen Oct 19 '17 at 21:27
  • \$\begingroup\$ @Xcali #testingonproduction \$\endgroup\$ – NieDzejkob Oct 21 '17 at 6:15
  • 2
    \$\begingroup\$ @NieDzejkob There's no better place. That's the only way you know it will work in production. \$\endgroup\$ – Xcali Oct 21 '17 at 17:44

Probably not the most golfed it could be, but it works.

-6 bytes thanks to ovs

-77 Bytes thanks to NieDzejkob and Jonathan French

Python 3, 329 323 bytes 246 bytes

import re;n=input()
for a in re.finditer('(\w)\\1+',n):b=a.group();n=n.replace(b,str(len(b))+b[0],1)
for A,B,C in[('abcdefghikloqstvxyw','@8(63#9#1<1095+>%?','uu'),('ilsvw','!i$<','2u')]:
	for a,b in zip(A,list(B)+[C]):n=n.replace(a,b,1)

Try it online!

  • 1
    \$\begingroup\$ I think you may drop .lower() \$\endgroup\$ – mdahmoune Oct 19 '17 at 17:46
  • \$\begingroup\$ That makes sense, I wasn't sure whether I needed to handle uppercase or not. \$\endgroup\$ – reffu Oct 19 '17 at 17:54
  • \$\begingroup\$ 321 bytes. \$\endgroup\$ – Jonathan Frech Oct 21 '17 at 4:35
  • 1
    \$\begingroup\$ 320 bytes. \$\endgroup\$ – Jonathan Frech Oct 21 '17 at 4:46
  • 2
    \$\begingroup\$ Actually, your answer doesn't work. jjjmjjjj should output 3jm4j but outputs 3jm3jj. Edit: 258 bytes with this problem fixed \$\endgroup\$ – NieDzejkob Oct 21 '17 at 12:23

Retina, 166 124 bytes


Try it online! Explanation:


Replace a run of repeated letters with the length and the letter.


Match the first occurrence of the letters a to y and mark them with a placeholder.


Fix the first occurrence of w.


Fix the first occurrence of all the other letters from a to y and delete the placeholders.


Mark the (originally) second occurrence of the letters i, l, s, v, or w with a placeholder.


Fix the second occurrence of w.


Fix the second occurrence of the other four letters.

  • \$\begingroup\$ Do you think it’s possible to golf it further? \$\endgroup\$ – mdahmoune Oct 19 '17 at 16:07
  • \$\begingroup\$ @mdahmoune Yes, I think I can save 33 bytes. \$\endgroup\$ – Neil Oct 19 '17 at 16:21
  • \$\begingroup\$ I up-voted your answer :) it will be great if your save the 33 bytes ;) \$\endgroup\$ – mdahmoune Oct 19 '17 at 16:33
  • \$\begingroup\$ @mdahmoune Good news, I actually saved 42 bytes! \$\endgroup\$ – Neil Oct 19 '17 at 18:29
  • \$\begingroup\$ Great, your code is the second shortest ;) \$\endgroup\$ – mdahmoune Oct 19 '17 at 18:42

Haskell, 221 218 213 bytes

($(f<$>words"w2u li i! s$ v< a@ b8 c( d6 e3 f# g9 h# i1 k< l1 o0 q9 s5 t+ v> wuu x% y?")++[r]).foldr($)
f _ s=s
r(a:b)|(p,q)<-span(==a)b=[c|c<-show$1+length p,p>[]]++a:r q
r s=s

Try it online!

Abuses foldr to run the string through a sequence of string transformations backwards. The sequence "starts" with r which does the repetition count replacement by using span to break the tail of the string when it stops being equal to the head. If the first part of that is non-empty it's a repetition so we print the length +1. Next we curry an argument into f for each character replacement in (reverse) order. The replacements are encoded as a single string with the first character being the character to be replaced and the rest as the string (since the w replacements are multiple characters) to go in its place. I put these encoded strings in one big string separated by spaces so that words can break it into a list for me.

EDIT: Thanks @Laikoni for saving me 5 bytes! That was a clever use of $ I didn't think of. I also didn't know that <- trick.

  • \$\begingroup\$ Thanx for detailed explanation ;) \$\endgroup\$ – mdahmoune Oct 19 '17 at 19:50
  • 1
    \$\begingroup\$ You can use (p,q)<-span(==a)b instead of let(p,q)=span(==a)b and p>[] instead of p/=[]. \$\endgroup\$ – Laikoni Oct 19 '17 at 21:03
  • 2
    \$\begingroup\$ Save two more bytes by making m pointfree: ($(f<$>words"w2u ... y?")++[r]).foldr($) Try it online! \$\endgroup\$ – Laikoni Oct 19 '17 at 21:11

Lua, 173 bytes

s=...for c,r in("uua@b8c(d6e3f#g9h#i1i!jjk<l1limmnno0ppq9rrs5s$t+v>v<wuuw2ux%y?zz"):gmatch"(.)(.u?)"do s=s:gsub(c..c.."+",function(p)return#p..c end):gsub(c,r,1)end print(s)

Try it online!

Ungolfed and explained:

s = ...

--This string contains every character to replace, followed by
--the character(s) it should be replaced with.
--It also contains all characters for which repeated sequences
--of them should be replaced by "<number><character>". That is,
--all letters in the alphabet. This way, a single loop can do
--both the "replace repeated characters" and "encode characters"
--operations, saving a for loop iterating over the alphabet.
--Characters that shouldn't be replaced will be replaced with
--In order to avoid matching half of the "replace u with u"
--command as the replace part of another command, "uu" is placed
--at the beginning of the string. This ensures that only the
--2-character replacements for "w" get an extra "u".

cmdstring = "uua@b8c(d6e3f#g9h#i1i!jjk<l1limmnno0ppq9rrs5s$t+v>v<wuuw2ux%y?zz"

--Iterate over all the search/replace commands.
--The character to replace is in the "c" variable, the string to
--replace it with is in "r".
--Due to the dummy search/replace commands (i.e. "mm") placed
--in the string, this loop will also iterate over all letters
--of the alphabet.

for c,r in cmdstring:gmatch("(.)(.u?)") do
	--First, replace any occurences of the current letter
	--multiple times in a row with "<number><letter>".
	s = s:gsub(c..c.."+", function(p)
		return #p .. c
	--Then, replace the first occurence of the letter
	--with the replacement from the command string.
	s = s:gsub(c, r, 1)

  • \$\begingroup\$ Lol lua :) good job \$\endgroup\$ – mdahmoune Oct 20 '17 at 6:44

C# (.NET Core), 317, 289, 279 Bytes

p=>{string r="",l=r,h=r,c="a@b8c(d6e3f#g9h#i1i!k<l1lio0q9s5s$t+v>v<wuw2x%y?";int i=0,n=p.Length,d,a=1;for(;i<n;i++){h=p[i]+"";if(h==p[(i==n-1?i:i+1)]+""&&i!=n-1)a++;else{d=c.IndexOf(h);if(d>=0&&d%2<1){l=c[d+1]+"";h=l=="u"?"uu":l;c=c.Remove(d,2);}r+=a>1?a+""+h:h;a=1;}}return r;};

Try it Online!

I hope it's ok to receive a char array as an input and not a string.


string result = "", casesCharReplacement = result, currentChar = result, cases = "a@b8c(d6e3f#g9h#i1i!k<l1lio0q9s5s$t+v>v<wuw2x%y?";
int i = 0, n = pas.Length, casesIndex, charAmounts = 1;

// For every char in the pass.
for (; i < n; i++)
    currentChar = pas[i] + "";
    // if the next char is equal to the current and its not the end of the string then add a +1 to the repeated letter.
    if (currentChar == (pas[(i == n - 1 ? i : i + 1)] + "") && i != n - 1)
        // Finished reading repeated chars (N+Char).
        casesIndex = cases.IndexOf(currentChar);
        // Look for the replacement character: only if the index is an even position, otherwise I could mess up with letters like 'i'.
        if (casesIndex >= 0 && casesIndex % 2 < 1)
            casesCharReplacement = cases[casesIndex + 1]+"";
            // Add the **** +u
            currentChar = casesCharReplacement == "u"?"uu": casesCharReplacement;
            // Remove the 2 replacement characters (ex: a@) as I won't need them anymore.
            cases = cases.Remove(casesIndex, 2);
        // if the amount of letters founded is =1 then only the letter, otherwise number and the letter already replaced with the cases.
        result += charAmounts > 1 ? charAmounts + ""+currentChar : currentChar;
        charAmounts = 1;
return result;
  • 1
    \$\begingroup\$ Yes it’s ok :) for the input \$\endgroup\$ – mdahmoune Oct 21 '17 at 3:01

C++, 571 495 478 444 bytes

-127 bytes thanks to Zacharý

#define F r.find(
#define U(S,n)p=F s(S)+b[i]);if(p-size_t(-1)){b.replace(i,1,r.substr(p+n+1,F'/',n+p)-p-2));r.replace(p+1,F'/',p+1)-p,"");}
#define V(A)i<A.size();++i,c
using s=std::string;s m(s a){s b,r="/a@/b8/c(/d6/e3/f#/g9/h#/i1//i!/k</l1//li/o0/q9/s5//s$/t+/v>/wuu//w2u/x%/y?/";int c=1,i=0;for(;V(a)=1){for(;a[i]==a[i+1]&&1+V(a)++);b+=(c-1?std::to_string(c):"")+a[i];}for(i=0;V(b)){auto U("/",1)else{U("//",2)}}return b;}

the "/a@/b8/c(/d6/e3/f#/g9/h#/i1//i!/k</l1//li/o0/q9/s5//s$/t+/v>/wuu//w2u/x%/y?/" string is used to transform from one character to others. 1 / means that the first "next char" should be replaced by what follow the next /, 2 means that the second "next char" should be replaced by what follows.

Try it online

  • \$\begingroup\$ Great, could you please add a tio.run link ? \$\endgroup\$ – mdahmoune Oct 21 '17 at 9:38
  • \$\begingroup\$ @mdahmoune TIO link is added, with the code to test for your test cases :) \$\endgroup\$ – HatsuPointerKun Oct 21 '17 at 10:04
  • \$\begingroup\$ 494 bytes, and update the TIO link accordingly if you change it. \$\endgroup\$ – Zacharý Oct 22 '17 at 1:04
  • \$\begingroup\$ @Zacharý You need to put a space between the macro name and the macro content, otherwise, it throws an error when compiling with C++ 17. Also, do you know how to delete a TIO link ? ( since the old one is useless ) \$\endgroup\$ – HatsuPointerKun Oct 22 '17 at 9:44
  • 1
    \$\begingroup\$ 444 bytes \$\endgroup\$ – Zacharý May 24 '18 at 17:50

R, 224 219 bytes


Try it online!

Nasty, but the main part is the iterative substitution in the Reduce. sub changes only the first occurrence of the match.

Thanks to JayCe for pointing out a nice golf!

  • \$\begingroup\$ Good job :))))) \$\endgroup\$ – mdahmoune Oct 19 '17 at 22:23
  • \$\begingroup\$ save 1 byte by rearranging args. Doesn't make a huge difference I know ;) \$\endgroup\$ – JayCe May 24 '18 at 18:32
  • \$\begingroup\$ @JayCe I found some more bytes :-) \$\endgroup\$ – Giuseppe May 24 '18 at 18:37

Perl 5, 123 bytes

122 bytes code + 1 for -p.

Developed independently from @Xcali's answer, but using a very similar process.


Try it online!


Python 2, 220 216 194 190 188 bytes

import re
S=re.sub(r'(.)\1+',lambda m:`len(m.group(0))`+m.group(1),input())
for a,b in zip('abcdefghiiklloqsstvvxyww',list('@8(63#9#1!<1i095$+><%?')+['uu','2u']):S=S.replace(a,b,1)
print S

Try it online!

Python 3, 187 bytes

import re
S=re.sub(r'(.)\1+',lambda m:str(len(m.group(0)))+m.group(1),input())
for a,b in zip('abcdefghiiklloqsstvvxyww',[*'@8(63#9#1!<1i095$+><%?','uu','2u']):S=S.replace(a,b,1)

Try it online!

  • \$\begingroup\$ Thanx Tfeld 192 bytes tio.run/… \$\endgroup\$ – mdahmoune Oct 20 '17 at 8:27
  • \$\begingroup\$ Great golfing ;) \$\endgroup\$ – mdahmoune Oct 20 '17 at 8:38
  • \$\begingroup\$ 186 bytes. You can also easily port this to Python 3 in 192 bytes, but I don't think it should be a separate answer. \$\endgroup\$ – NieDzejkob Oct 21 '17 at 13:36
  • \$\begingroup\$ @NieDzejkob It seems as though your golfed Python 2 version produces a different output than the OP's current version or your Python 3 version. \$\endgroup\$ – Jonathan Frech Oct 21 '17 at 17:10
  • \$\begingroup\$ @JomathanFrech sorry, as always testing on production. 188 bytes \$\endgroup\$ – NieDzejkob Oct 21 '17 at 18:14

Pip, 103 102 bytes


Try it online!


The code does three steps of transformation:

aR:`(.)\1+`#_.B  Process runs of identical letters

a                1st cmdline argument
 R:              Do this replacement and assign back to a:
   `(.)\1+`       This regex (matches 2 or more of same character in a row)
           #_.B   Replace with callback function: concatenate (length of full match) and
                  (first capture group)
                  Note: #_.B is a shortcut form for {#a.b}

Fm"..."Z"..."I#Ya@?@maRA:ym@1  Do the bulk of rules 2-25

  "..."                        String of letters to replace
       Z"..."                  Zip with string of characters to replace with
Fm                             For each m in the zipped list:
                   @m           First item of m is letter to replace
                a@?             Find its index in a, or nil if it isn't in a
               Y                Yank that into y
             I#                 If len of that is truthy:*
                     aRA:        Replace character in a at...
                         y        index y...
                          m@1     with second item of m

aR'W"uu"R'U"2u"  Clean up substitution
                 In the previous step, the replacements each had to be a single character.
                 This doesn't work for uu and 2u, so we use W and U instead (safe, since
                 uppercase letters won't be in the input) and replace them here with the
                 correct substitutions.
aR'W"uu"         In a, replace W with uu
        R'U"2u"  and U with 2u
                 and print the result (implicit)

* We need to test whether a@?m@0 is nil. It's not enough to test that it's truthy, since 0 is a legitimate index that is falsey. Pip doesn't have a short builtin way to test if a value is nil, but testing its length works well enough in this case: any number will have length at least 1 (truthy), and nil has length of nil (falsey).


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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