Given an email address, the result of a transformation applied to that email address, and a second email address, return the output of the same transformation applied to the second email address.

The email addresses will all have the following structure:

A string of positive length containing alphanumeric characters and at most one . (the local part), followed by an @ symbol, followed by a string of positive length containing alphanumeric sumbols (the domain), followed by a . symbol, and a final string of positive length containing alphanumeric characters (the TLD).

There are four allowed transformations:

When more than one transformation is possible, you can give the output of any of the possibilities. Whitespace at the start and end of output don't matter, but in the middle does (i.e. if you split a.b to A B there should be just one space in the middle [and any number at the start and end of output], but if you split a., then A with any number of spaces on either side are all acceptable).

Examples (input | output):

[email protected], John Doe, [email protected]         | Phillip Maini
[email protected], John Doe, [email protected]         | Phillip Maini
[email protected], foo.bar, [email protected]           | gee.whizz
[email protected], foo.bar, [email protected]           | gEe.Whizz
[email protected], comedy, [email protected] | office
[email protected], Jones, [email protected]                                     | A
[email protected], [email protected], [email protected]                                | [email protected]
[email protected], .jones, [email protected]                                    | a.
[email protected], x, [email protected]                                         | 3
[email protected], [email protected], [email protected]                                           | [email protected]
[email protected], John Jones, [email protected]           | 1in Thehand
[email protected], Chicken Soup, [email protected]                    | Fab
[email protected], lange, [email protected]                          | fat.so
[email protected], Lange, [email protected]                          | {fat.so, Fat So} # either acceptable
[email protected], chicken, [email protected]              | {horse, pig} # either acceptable

Usual rules and loopholes apply.

  • \$\begingroup\$ Shouldn't the last test case return "horse"? I don't see why it can return "pig" instead. \$\endgroup\$ Oct 30, 2017 at 16:25
  • 3
    \$\begingroup\$ @EriktheOutgolfer because the 4th transformation is to return just the domain (the part between @ and final .). Since the local part and domain are both chicken, it's ambiguous whether it's the 2nd or 4th transformation \$\endgroup\$
    – LangeHaare
    Oct 30, 2017 at 16:28
  • \$\begingroup\$ Oh, I misinterpreted that. \$\endgroup\$ Oct 30, 2017 at 16:30
  • \$\begingroup\$ May we require that the relevant input is formatted with the space in all cases (e.g. in the test where the output is A [with a trailing space] that the second input be Jones [with a leading space])? \$\endgroup\$ Oct 30, 2017 at 21:08
  • \$\begingroup\$ I don't understand why [email protected], Jones, [email protected] is A - if jones is matched that means the matching part is the part between the first period and the @ symbol. But that would result in an empty string because the a is before the first period and not after. \$\endgroup\$ Oct 31, 2017 at 0:17

11 Answers 11


Java 8, 254 240 236 bytes

(a,b,c)->{String A[]=a.split("@"),C[]=c.split("@"),x="";for(String p:C[0].split("\\."))x+=(p.charAt(0)+"").toUpperCase()+p.substring(1)+" ";return a.equals(b)?c:A[0].equals(b)?C[0]:A[1].split("\\.")[0].equals(b)?C[1].split("\\.")[0]:x;}

-4 bytes thanks to @LukeStevens.


Try it here.

(a,b,c)->{                  // Method with three String parameters and String return-type
  String A[]=a.split("@"),  //  Split `a` by "@" into two parts
         C[]=c.split("@"),  //  Split `c` by "@" into two parts
         x="";              //  Temp-String
  for(String p:C[0].split("\\.")) 
                            //  Loop over the first part of `c`, split by dots
    x+=                     //   Append String `x` with:
                            //    The first character as uppercase
       +p.substring(1)      //    + the rest of the String
       +" ";                //    + a space
                            //  End of loop (implicit / single-line body)
  return a.equals(b)?       //  If input `a` and `b` are exactly the same:
    c                       //   Return `c`
   :A[0].equals(b)?         //  Else-if the first part of `a` equals `b`:
    C[0]                    //   Return the first part of `c`
                            //  Else-if the domain of `a` equals `b`
    C[1].split("\\.)[0]     //   Return the domain of `c`
   :                        //  Else:
    x;                      //   Return String `x`
}                           // End of method
  • 1
    \$\begingroup\$ You can knock off 4 bytes by using (p.charAt(0)+"").toUpperCase() instead of Character.toUpperCase(p.charAt(0)). \$\endgroup\$ Oct 31, 2017 at 10:17
  • \$\begingroup\$ @LukeStevens Thanks! I had (char)(p.charAt(0)&~32) at first, but this didn't work due to the 1in Thehand test case. But uppercasing it as String is indeed shorter than Character.toUpperCase, so thanks! \$\endgroup\$ Oct 31, 2017 at 11:18

Haskell, 208 bytes

import Data.Char
s c""=[]
s c a=w:f t where
 f(_:y)=s c y
 f _=[]
u(x:y)=toUpper x:y
l=h.s '@'
f x y=h[t|t<-[id,l,unwords.filter(/="").map u.s '.'.l,h.s '.'.last.s '@'],t x==y]

Try it online!

It is sad I had to spend 59 bytes on reinventing split (s).

The solution creates a list of transformations and returns the first one that leads to the expected result.

  • \$\begingroup\$ Welcome to the site! I don;t know Haskell, but is it possible to remove any of the whitespace characters, such as newlines and spaces? \$\endgroup\$ Oct 31, 2017 at 14:36
  • \$\begingroup\$ Nice first answer! You might be interested in our collection of tips for golfing in Haskell, especially this and this should save some bytes. \$\endgroup\$
    – Laikoni
    Oct 31, 2017 at 21:25
  • \$\begingroup\$ Also feel free to join us in Of Monads and Men, a chat room for golfing and general discussion of Haskell. \$\endgroup\$
    – Laikoni
    Oct 31, 2017 at 21:27

Jelly, 40 bytes

Pre-emptive thanks to Erik the Outgolfer for noticing the failure of using Œt (title-case) and hence Œu1¦€K over ŒtK

-1 byte thanks to Erik the Outgolfer (rearrangement of ⁵⁸ç⁹¤Ŀ to çµ⁵⁸Ŀ)


A full program taking exampleEmail, exampleOutput, realEmail and printing the result.

Try it online!


Performs all four transforms (plus a precursor one), finds the first one that yields the example from the first email, then applies it to the second email:

            - Link 1, do nothing: email
            - do nothing but return the input

ÑṪṣ”.Ḣ      - Link 2, the domain: email
Ñ           - call the next link (3) as a monad (split at "@")
 Ṫ          - tail
  ṣ”.       - split at "."
     Ḣ      - head

ṣ”@         - Link 3, split at @: email
ṣ”@         - split at "@"

ÇḢ          - Link 4, local part: email
Ç           - call the last link (3) as a monad (split at "@")
 Ḣ          - head

Çṣ”.Œu1¦€K  - Link 5, name-ified: email
Ç           - call the last link (4) as a monad (get the local part)
 ṣ”.        - split at "."
       ¦€   - for €ach sparsley apply:
      1     - ...to index: 1
    Œu      - ...action: uppercase
         K  - join with space(s)

⁹ĿðЀ5i     - Link 6, index of first correct link: exampleEmail; exampleOutput
   Ѐ5      - map across (implicit range of) 5 (i.e. for each n in [1,2,3,4,5]):
  ð         -   dyadicly (i.e. with n on the right and exampleEmail on the left):
 Ŀ          -     call referenced link as a monad:
⁹           -     ...reference: chain's right argument, n
      i     - first index of exampleOutput in the resulting list

çµ⁵⁸Ŀ       - Main link: exampleEmail; exampleOutput
ç           -   call the last link (6) as a dyad (get the first "correct" link index)
 µ          - monadic chain separation (call that L)
   ⁸        - chain's left argument, L
    Ŀ       - call the link at that reference as a monad with input:
  ⁵         -   program's third input, realEmail


  1. Assumes the input exampleOutput is strictly the same as the output would be.

  2. The "precursor" (the result of link 3) is tested for matching the exampleOutput, but it won't match unless the exampleOutput itself is a list of lists of characters. As such the inputs should probably be quoted (Python formatting may be used here) to avoid the possibility of interpreting it as such.


Python 2, 135 bytes

def f(x):S,D=x.split('@');return x,S,' '.join(map(str.capitalize,S.split('.'))),D.split('.')[0]
print f(x)[f(s).index(r)]

Try it online!

  • \$\begingroup\$ -3 bytes by moving strip \$\endgroup\$
    – ovs
    Oct 30, 2017 at 21:31
  • \$\begingroup\$ @ovs thanks, anyways rules changed to remove the need for it \$\endgroup\$ Oct 31, 2017 at 12:43

JavaScript (ES6), 145 bytes

Invoke with currying syntax, e.g. f('[email protected]')('Chicken Soup')('[email protected]')

x=>y=>[x=>x,s=x=>x.split`@`[0],x=>s(x).split`.`.map(w=>w&&w[0].toUpperCase()+w.slice(1)).join` `.trim(),x=>/@(.+)\./.exec(x)[1]].find(f=>f(x)==y)

f=x=>y=>[x=>x,s=x=>x.split`@`[0],x=>s(x).split`.`.map(w=>w&&w[0].toUpperCase()+w.slice(1)).join` `.trim(),x=>/@(.+)\./.exec(x)[1]].find(f=>f(x)==y)

for(const [x, y, z] of [
['[email protected]', 'John Doe', '[email protected]'], // Phillip Maini
['[email protected]', 'John Doe', '[email protected]'], // Phillip Maini
['[email protected]', 'foo.bar', '[email protected]'], // gee.whizz
['[email protected]', 'foo.bar', '[email protected]'], // gEe.Whizz
['[email protected]', 'comedy', '[email protected]'], // office
['[email protected]', 'Jones', '[email protected]'], // A
['[email protected]', '[email protected]', '[email protected]'], // [email protected]
['[email protected]', '.jones', '[email protected]'], // a.
['[email protected]', 'x', '[email protected]'], // 3
['[email protected]', '[email protected]', '[email protected]'], // [email protected]
['[email protected]', 'John Jones', '[email protected]'], // 1in Thehand
['[email protected]', 'Chicken Soup', '[email protected]'], // Fab
['[email protected]', 'lange', '[email protected]'], // fat.so
['[email protected]', 'Lange', '[email protected]'], // {fat.so, Fat So} # either acceptable
['[email protected]', 'chicken', '[email protected]'], // {horse, pig} # either acceptable
]) console.log( f(x)(y)(z) )


Mathematica, 217 bytes


Try it online!


Ruby, 117 106 102 bytes

->a,b,c{r=[/.*/,/(?<=@)\w*/,/[^@]*/].find{|x|r=c[x];a[x]==b}?r:r.sub(?.," ").gsub(/\b(.)/){$1.upcase}}

Try it online!


CJam, 42


Try it online


q~        read and evaluate the input (given as 3 quoted strings)
@         bring the first string to the top of the stack
{…}:T     define a function T that calculates the 4 transformations of a string:
  [       begin array
  _\      duplicate the string, and swap with the other copy to bring it in the array
           (1st transformation)
  '@/~    split by '@' and put the 2 pieces on the stack
  './0=   split the 2nd piece by '.' and keep the first part
           (4th transformation)
  \_      swap with the piece before '@' and duplicate it
           (2nd transformation)
  '.%     split by '.', removing the empty pieces
  {…}%    transform the array of pieces
    (eu   take out the first character and capitalize it
    \+    prepend it back to the rest
  S*      join the pieces by space
           (3rd transformation)
  ]       end array
~         execute the function on the first string
@a        bring the 2nd string to the top of the stack, and wrap it in an array
#         find the position of this string in the array of transformations
\T        bring the 3rd string to the top and call function T
=         get the transformation from the array, at the position we found before

PHP 7.1, 176 bytes

<?$e=explode;[,$p,$q,$r]=$argv;echo$p==$q?$r:($e('@',$p)[0]==$q?$e('@',$r)[0]:($e('.',$e('@',$p)[1])[0]==$q?$e('.',$e('@',$r)[1])[0]:ucwords(join(' ',$e('.',$e('@',$r)[0])))));

Try it online!

PHP < 7.1, 180 bytes

Versions under 7.1 would need to change the [,$p,$q,$r]=$argv to list(,$p,$q,$r)=$argv, adding 4 bytes.


GNU sed, 105 + 1(r flag) = 106 bytes

The first three s commands check for the identity, local part and domain transformations respectively. If one transformation matches, then it is applied to the second email address and the following s commands will fail due to a lack of the input format.

s:.*,([^.]*)\.?(.*)@.*:\u\1 \u\2:

Try it online!

The local part split transformation (last s command) is the most expensive to check, in terms of bytes, therefore I placed it at the end and assumed it matches (since the other ones failed by that time), going directly to its application.


Jelly, 43 bytes


Try it online!

  • \$\begingroup\$ Would ŒtK work in place of Œu1¦€K to save 3? \$\endgroup\$ Oct 30, 2017 at 21:12
  • \$\begingroup\$ ...and what's the need for Œl? \$\endgroup\$ Oct 30, 2017 at 21:17
  • \$\begingroup\$ ^ ah I see that 1in.thehand would not work with ŒtK. \$\endgroup\$ Oct 30, 2017 at 21:24
  • \$\begingroup\$ @JonathanAllan Yep, that's the reason why I didn't use that, and also the reason ovs's (now deleted) answer was invalid (str.title). \$\endgroup\$ Oct 31, 2017 at 12:26

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.