Shrink each word in a string of group of strings to single letters delineated by spaces or punctuation.


I'm a little teapot,  short and stout. Here is my handle, here is my spout. When I get all steamed up - hear me shout!   Tip me over and pour me out. 


I' a l t, s a s. H i m h, h i m s. W I g a s u - h m s! T m o a p m o. 

Edit - if there are multiple spaces, preserve only one space. All punctuation should be preserved, I missed the apostrophe. Yes this is code golf :-).

  • 1
    \$\begingroup\$ Can there be multiple spaces between the words? Do we have to preserve them? \$\endgroup\$
    – Dennis
    May 24, 2015 at 20:57
  • 8
    \$\begingroup\$ Also, which characters exactly count as punctuation? \$\endgroup\$
    – Dennis
    May 24, 2015 at 21:03
  • 1
    \$\begingroup\$ What is the required behavior for numbers or other characters besides punctuation (+ etc.) \$\endgroup\$
    – grovesNL
    May 24, 2015 at 21:40
  • 1
    \$\begingroup\$ Will there ever be more than one punctuation within a word? Something like O'Leary-Clarence-DeVois would become O'--? \$\endgroup\$
    – hmatt1
    May 24, 2015 at 21:42
  • 8
    \$\begingroup\$ You can accept an answer whenever you like, but it's better to leave some time (days) before closing a challenge. \$\endgroup\$
    – edc65
    May 24, 2015 at 22:00

15 Answers 15


CJam, 13 bytes


Works if I can consider only the common punctuation characters, and the output can have trailing spaces. (Thanks to Dennis.)

This question needs much more clarification...

CJam, 17 16 bytes


Try it online.


r          e# Read one word from input.
{          e# While it is not EOF:
    (\     e# Extract the first character.
    eu     e# Convert the rest to uppercase.
    _el    e# And lowercase.
    f&     e# Delete characters in the first string if not in the second string.
    S      e# Append a space.
    r      e# Read the next word.
&          e# Discard the last space by intersecting with empty string.
  • \$\begingroup\$ Can you add a link to test it please? I'm on mobile. \$\endgroup\$
    – Cthanatos
    May 24, 2015 at 21:22
  • \$\begingroup\$ @Cthanatos Added. \$\endgroup\$
    – jimmy23013
    May 24, 2015 at 21:26
  • 1
    \$\begingroup\$ r pushes an empty string on EOF, so this works as well: r{(\eu_elf&Sr}h; \$\endgroup\$
    – Dennis
    May 25, 2015 at 0:37
  • 1
    \$\begingroup\$ @Dennis I'm sure I have seen code like that many times, but still didn't remember... Thanks. But the ; makes no sense then. \$\endgroup\$
    – jimmy23013
    May 25, 2015 at 0:44
  • 1
    \$\begingroup\$ If required, you could still get rid of it with &. Also, depending on what exactly counts as punctuation, '@, would be a shorter alternative to eu_el. \$\endgroup\$
    – Dennis
    May 25, 2015 at 2:02

Pyth, 14 bytes


Try it online: Demonstration


                 implicit: z = input string
            cz   split z by spaces
  m              map each word d to:
    hd              first letter of d
   +                +
       rtd0         (lowercase of d[1:]
      -    G         but remove all chars of "abc...xyz")
jd               join resulting list by spaces and print
  • \$\begingroup\$ Is this duplicating hyphens? \$\endgroup\$
    – Cthanatos
    May 24, 2015 at 21:19
  • \$\begingroup\$ @Cthanatos Should work now. \$\endgroup\$
    – Jakube
    May 24, 2015 at 21:25
  • \$\begingroup\$ @grovesNL can you think of a sentence that one might come across in regular writing ie a book, news article where numbers within a sentence might be an issue or come up? \$\endgroup\$
    – Cthanatos
    May 24, 2015 at 21:45
  • \$\begingroup\$ @Cthanatos: There are plenty of cases where numbers are used in books or news articles. "Over 200 respondents..." "The lot is 50 acres..." "It is capable of holding approximately 20 liters..." \$\endgroup\$
    – grovesNL
    May 24, 2015 at 21:54
  • \$\begingroup\$ Touché... Good point. \$\endgroup\$
    – Cthanatos
    May 24, 2015 at 21:56

Python 3.4, 94 92 82 77 bytes

print(*[w[0]+''.join(c[c.isalpha():]for c in w[1:])for w in input().split()])

I'm new to code golfing but I thought I'd give it a try! This one's not a winner, but it was fun.

This just splits the string, taking the first character of each word along with any punctuation in the rest of the word.

*edited with changes by FryAmTheEggman, DLosc

  • \$\begingroup\$ You can use python's starred argument passing to save some bytes, and inverting the condition seems to save 1 byte (although it still looks suspiciously golfable). Here's what I got: print(*[w[0]+''.join([c for c in w[1:]if 1-c.isalpha()])for w in input().split()]) \$\endgroup\$ May 24, 2015 at 23:29
  • \$\begingroup\$ @FryAmTheEggman Ah, thanks! I forgot about starred argument passing. \$\endgroup\$
    – Robotato
    May 25, 2015 at 0:31
  • 2
    \$\begingroup\$ No need for the square braces around the inner comprehension--join can take a bare generator as an argument. Also, here's a string-slicing way of doing the "if not isalpha" logic: c[c.isalpha():]for c in w. Should get you down to 77 bytes. :^) \$\endgroup\$
    – DLosc
    May 25, 2015 at 3:22
  • \$\begingroup\$ @DLosc That string-slicing trick is clever, thanks! I'll have to remember that one. \$\endgroup\$
    – Robotato
    May 25, 2015 at 5:51

Jelly, 14 bytes


Try it online!

Solution done with Mr. Xcoder and caird coinheringaahing in Jelly Hypertraining chat room.

Alternative 14 bytes: Try it online!


sed (39 chars)

Just a couple of regular expressions:

sed 's+\<\(.\)[A-Za-z]*+\1+g;s+  *+ +g'
  • 2
    \$\begingroup\$ We usually not count the interpreter's name and the additional syntax required by shell to pass the code or data correctly to the interpreter. Your actual Sed code has only 32 characters. \$\endgroup\$
    – manatwork
    May 25, 2015 at 7:39

Lua - 126 characters

Lua isn't much of a code golfing language, but I gave it a shot:

a=''for b in string.gmatch( c, '%S+%s?' )do d=(b:match('%w')or''):sub(1,1)e=b:match('[^%s%w]')or''a=a..d..e..' 'end print( a )

This assumes that c is the string.

Here it is cleaned up for readability:

local string = [[I'm a little teapot,  short and stout. Here is my handle, here is my 
spout. When I get all steamed up - hear me shout!   Tip me over and pour me out.]]

local final = ''
for word in string.gmatch( string, '%S+%s?' ) do 
    local first = ( word:match( '%w' ) or '' ):sub( 1, 1 )
    local second = word:match( '[^%s%w]' ) or ''
    final = final .. first .. second .. ' '
print( final )

You can test it here (copy and paste it. For the first on you also have to do c = "I'm a little ....) For some reason the online demo of Lua won't let you input variables using io.read...


PowerShell, 56 bytes

%{($_-split' '|%{$_[0]+($_-replace'[a-z]','')})-join' '}

Javascript (ES6) 72 68 bytes

f=x=>x.split(/\s+/).map(x=>x.replace(/^(.)|[a-z]/gi,'$1')).join(' ')
<input id="input" value="I'm a little teapot,  short and stout. Here is my handle, here is my spout. When I get all steamed up - hear me shout!   Tip me over and pour me out. " />
<button onclick="output.innerHTML=f(input.value)">Run</button>
<br /><pre id="output"></pre>


    x.split(/\s+/). // split input string by 1 or more spaces
    map(x=> // map function to resulting array
        x.replace(/^(.)|[a-z]/gi, '$1') // capture group to get the first character
                                        // replace all other letters with empty string
    join(' ') // join array with single spaces

C99 - 170 169 bytes



main(int argc, char**a) {
        for(e=b;*++b&&*b-32;); //scan for first space or end of word
        *b=0; //mark end of word
        for(;b[1]==32;++b); //skip following spaces
        d=strpbrk(e,"!',-."); //find punctuation
        if(d&&d-e) //append punctuation if any, and it's not the word itself
        *c++=32; //append space
    *c=0; //mark end of line


gcc -std=c99 test.c -o test
./test "I'm a little teapot,  short and stout. Here is my handle, here is my spout. When I get all steamed up - hear me shout!   Tip me over and pour me out."


I' a l t, s a s. H i m h, h i m s. W I g a s u - h m s! T m o a p m o.

Java 8, 87 bytes

s->{for(String x:s.split(" +"))System.out.print(x.replaceAll("^(.)|[a-z]+","$1")+" ");}


Try it here.

s->{                                  // Method with String parameter and no return-type
  for(String x:s.split(" +"))         //  Split the input on one or multiple spaces
                                      //  And loop over the substrings
    System.out.print(                 //   Print:
      x.replaceAll("^(.)|[a-z]+","$1")//    Regex to get the first letter + all non-letters
      +" ");                          //    + a space delimiter
                                      //  End of loop (implicit / single-line body)
}                                     // End of method

Regex explanation:

x.replaceAll("           ","  ") # Replace the match of String1 with String2, in String `x`
             "           "       # Regex to match:
              ^(.)               #  The first character of String `x`
                  |[a-z]+        #  Or any one or multiple lowercase letters
                           "  "  # Replace with:
                            $1   #  The match of the capture group (the first character)

So it basically removes all lowercase letters of a String, except the very first one.


Perl 5, 34 bytes

33 bytes code + 1 for -p.

s!\S\K\S+| \K +!$&=~s/\w| //gr!ge

Try it online!


R, 46 45 bytes


This reads a line from STDIN and prints to STDOUT. It uses a regular expression to remove all characters after the first letter followed by any amount of punctuation.

Ungolfed + explanation:

# Read a string from STDIN and convert it to a character vector,
# splitting at spaces

input <- scan(what = "")

# Replace stuff with nothing using a regex.
# ^ start position anchor
# \w single "word" character
# \W* any amount of non-word (i.e. punctuation) characters
# \K move the match position forward
# \w* any number of word characters

replaced <- gsub("^\\w\\W*\\K\\w*", "", input, ignore.case = TRUE, perl = TRUE)

# Print the vector elements to STDOUT, separated by a space

cat(replaced, sep = " ")


> cat(gsub("^\\w\\W*\\K\\w*","",scan(,""),T,T))
1: I'm a little teapot,  short and stout. Here is my handle, here is my spout. When I get all steamed up - hear me shout!   Tip me over and pour me out. 

I' a l t, s a s. H i m h, h i m s. W I g a s u - h m s! T m o a p m o.

05AB1E, 13 bytes


Try it online!


#õKεćsDáмJ}ðý  Full program
#              Split on spaces
 õK            Remove empty strings from the list
   ε           For each...
    ć             push a[1:], a[0]
     s            Swap
      D           Duplicate
       á          Push only letters of a
        м         pop a,b => push a.remove(all elements of b)
         J        Join
          }    End for each
           ðý  Join with spaces

VBA (Excel), 141 133 Bytes

Using VBA Immediate Window, [A1] as Inputted Strings.

z=" "&[A1]:for a=2 to len(z):c=mid(z,a,1):[A2]=[A2]&IIF(mid(z,a-1,1)=" ",c,IIF(asc(lcase(c))>96 and asc(lcase(c))<123,"",c)):next:?[TRIM(A2)]

z=" "&[a1]:for a=2 to len(z):c=mid(z,a,1):e=asc(lcase(c)):[a2]=[a2]&iif(mid(z,a-1,1)=" ",c,IIF((e>96)*(e<123),"",c)):next:?[TRIM(A2)]

Perl 6, 15 bytes


Try it online!

  • \$\begingroup\$ Output doesn't match the example. \$\endgroup\$
    – Xcali
    Oct 19, 2017 at 22:23

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.