41
\$\begingroup\$

Note: The winning answer will be selected on 4/12/17 the current winner is Jolf, 1 byte.

I'm surprised that we haven't had a what's my middle name challenge on this site yet. I did alot of searching but found nothing. If this is a dup, please flag it as such.

Your challenge

Parse a string that looks like Jo Jean Smith and return Jean.

Test cases

Input: Samantha Vee Hills
Output: Vee

Input: Bob Dillinger
Output: (empty string or newline)

Input: John Jacob Jingleheimer Schmidt
Output: Jacob Jingleheimer

Input: Jose Mario Carasco-Williams
Output: Mario

Input: James Alfred Van Allen
Output: Alfred Van 

(That last one is incorrect technically, but fixing that would be too hard.)

Notes:

  • Names will always have at least 2 space-separated parts, with unlimited middle names between them or can be a list/array of strings.
  • Names may contain the alphabet (case-insensitive) and - (0x2d)
  • You may output a trailing newline.
  • You may require input to have a trailing newline.
  • Input from STDIN, a function parameter, or command-line argument is allowed, but hard-coding it in is not allowed.
  • Standard loopholes forbidden.
  • Output may be function return value, STDOUT, STDERR, etc.
  • Trailing spaces/newlines/tabs in the output are allowed.
  • Any questions? Comment below!

This is , so the shortest anwser in bytes wins!

\$\endgroup\$
20
  • 2
    \$\begingroup\$ Can the output be a list of strings? \$\endgroup\$ Commented Apr 2, 2017 at 14:34
  • 5
    \$\begingroup\$ If other formats than a space-separated string are allowed, please edit that into the specification. \$\endgroup\$ Commented Apr 2, 2017 at 14:46
  • 5
    \$\begingroup\$ @programmer5000: if the input can be a list of strings, how about the output? Is ["John", "Jacob", "Jingleheimer", "Schmidt"] -> ["Jacob", "Jingleheimer"] a valid solution? \$\endgroup\$
    – nimi
    Commented Apr 2, 2017 at 15:17
  • 3
    \$\begingroup\$ Are leading spaces allowed? \$\endgroup\$
    – betseg
    Commented Apr 2, 2017 at 15:32
  • 5
    \$\begingroup\$ @DJ Because "Van" isn't his middle name, it's part of his last name. A particularly vexing case is David Lloyd George, whose first name is David and last name is Lloyd George. Any attempt to parse real people's names like this is doomed. In fact, you can't even tell what the first and last names are (think Li Shi). \$\endgroup\$ Commented Apr 3, 2017 at 2:16

75 Answers 75

2
\$\begingroup\$

Matlab, 81, 79, 78, 55 Bytes

function x=a(s)
s=strsplit(s);x=strjoin(s(2:end-1));end

Takes in an input string, s, is split (by the default delimiter, whitespace char) into a cell array, from which the middle element is accessed. Then the middle elements are concatenated, or an empty string is returned.

Edit: thanks to Luis Mendo for saving 3 bytes!

Edit 2: Better solution from Ankit!

\$\endgroup\$
3
  • \$\begingroup\$ I am not a smart man! edited. \$\endgroup\$ Commented Apr 2, 2017 at 16:26
  • \$\begingroup\$ You can't use nnz on a cell array, but I did the other two changes :) \$\endgroup\$ Commented Apr 2, 2017 at 16:45
  • \$\begingroup\$ Suggested Edit by Ankit, who doesn't have enough rep to comment. (55 bytes): function x=a(s) s=strsplit(s);x=strjoin(s(2:end-1));end \$\endgroup\$
    – mbomb007
    Commented Apr 3, 2017 at 21:09
2
\$\begingroup\$

C, 42 bytes

f(char**b){for(;b[2];printf("%s ",*++b));}

The parameter is a NULL terminated array of pointers to char.

See it work here.

The command line arguments may also be used with the same function.

C, 51 bytes

main(a,b)char**b;{for(;b[3];printf("%s ",b++[2]));}

A full program. Input is done through command line arguments.

See it work here.

C, 54 bytes

f(char**b){*strrchr(*b=strchr(*b,32),32)=0;*b+=!!**b;}

The parameter is an in/out parameter.

See it work here.

\$\endgroup\$
3
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Commented Apr 3, 2017 at 20:10
  • \$\begingroup\$ I'm receiving the following error when compiling with Visual Studio 2012:error C2100: illegal indirection \$\endgroup\$
    – jdt
    Commented Apr 5, 2017 at 14:17
  • \$\begingroup\$ @JohanduToit VS is not C11 or even C99 conforming. My code is. As practical proof, both gcc and clang compile a valid program. \$\endgroup\$
    – 2501
    Commented Apr 5, 2017 at 20:08
2
\$\begingroup\$

Clojure, 43 bytes:

#(drop 1(butlast(read-string(str"("%")"))))

Here we read string as an edn data, then choosing its center.

Or for stdout, 57 bytes:

#(apply pr-str(drop 1(butlast(read-string(str"("%")")))))



You can also check it here.

\$\endgroup\$
4
  • \$\begingroup\$ Is the space in str " necessary? \$\endgroup\$ Commented Dec 14, 2018 at 16:50
  • \$\begingroup\$ @JonathanFrech it leads to "RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:221)" without space \$\endgroup\$
    – bbb1
    Commented Dec 14, 2018 at 16:55
  • \$\begingroup\$ @JonathanFrech I add link to online Clojure REPL, so you can check it. UPD: where it works... It's strange. \$\endgroup\$
    – bbb1
    Commented Dec 14, 2018 at 16:57
  • \$\begingroup\$ To me it looks like you changed it in your online REPL, did not change your post and said it would not work ... (TIO). \$\endgroup\$ Commented Dec 14, 2018 at 17:27
2
\$\begingroup\$

Powershell, 32 bytes

''+($args|sls ' .+ '|% m*)|% t*m

Test script:

$f = {
''+($args|sls ' .+ '|% m*)|% t*m
}

@(
    ,("Samantha Vee Hills"    ,"Vee")
    ,("Bob Dillinger"    ,"")
    ,("John Jacob Jingleheimer Schmidt"    ,"Jacob Jingleheimer")
    ,("Jose Mario Carasco-Williams"    ,"Mario")
    ,("James Alfred Van Allen"    ,"Alfred Van")
) | % {
    $name,$expected = $_
    $result = &$f $name
    "$($result-eq$expected): $expected"
}

Output:

True: Vee
True:
True: Jacob Jingleheimer
True: Mario
True: Alfred Van
\$\endgroup\$
2
\$\begingroup\$

Brainfuck, 98 bytes

>+[,>++++[<-------->-]<]>++++[<++++++++>-]<[>,]++++[<-------->-]<[[-]++++[<-------->-]<]<[<]>>[.>]

Explanation

>+[,>++++[<-------->-]<] Skip input until first space

>++++[<++++++++>-]< Store a Space char incase there is no middle name
[>,] Store input to a char array

++++[<-------->-]<[[-]++++[<-------->-]<] Goto the last space and zero the last space

<[<] Goto the start of the char array
>>[.>] Print the char array
\$\endgroup\$
2
\$\begingroup\$

AWK, 9 bytes

NF--,$1=a

Try it online!

NF--,     - Cut out the last argument (also eval's to "true")
     $1=a - Blank out the first argument

Since there's always at least 2 input fields NF--1 is always truthy, so the code prints $0.

In case the leading space isn't allowed (the question was asked in the comments under the initial posting but there was no response), then this is the shortest I've come up with.

AWK, 15 bytes

NF-=sub($1FS,a)

Try it online!

    sub($1FS,a)  - Remove the first field, plus space from the input
NF-=             - Decrement "NF" by one (the return from "sub")
\$\endgroup\$
4
  • \$\begingroup\$ Nice NF-- trick, but this outputs with one leading space, which I don't think is allowed. \$\endgroup\$
    – user41805
    Commented Sep 11, 2021 at 7:11
  • \$\begingroup\$ I couldn't tell if the leading space was allowed or not. Several people asked the in the comments about the question, but there was no response from the person who submitted it. I saw a couple others that seems to have a leading space though, so I assumed it was ok? \$\endgroup\$
    – cnamejj
    Commented Sep 11, 2021 at 7:40
  • \$\begingroup\$ Then out of curiousity, because I don't know much awk, how would you golfily fix this to remove the leading space? I've got tio.run/##SyzP/v/fz01XV01NxchWiUNJxUhHxdA28f//… so far \$\endgroup\$
    – user41805
    Commented Sep 11, 2021 at 11:14
  • \$\begingroup\$ Ha! I've been pondering ways to get rid of the leading space too... I'll post the one I came up with as an alternative in my answer. \$\endgroup\$
    – cnamejj
    Commented Sep 11, 2021 at 18:23
2
\$\begingroup\$

Factor, 17 16 bytes

[ rest 1 head* ]

(-1 byte as 1 head* is 1 byte shorter than but-last.)

Explanation:

It's a quotation (anonymous function) that takes a sequence of strings as input and leaves a sequence of strings as output.

  • rest Take all elements of a sequence but the first.
  • 1 head* Take all elements of a sequence but the last.
\$\endgroup\$
2
\$\begingroup\$

Fig, \$2\log_{256}(96)\approx\$ 1.646 bytes

pq

Try it online!

pq
 q # Remove the tail
p  # Remove the head
\$\endgroup\$
1
\$\begingroup\$

Python 2, 42 19 16 Bytes

lambda n:n[1:-1]

Try it online! Thanks to @Kritixi Lithos for saving 23 bytes! Thanks @math_junkie for saving 3 more bytes. For input, put each part of the name as a string within a list like so:

["Samantha", "Vee", "Hills"]

And yes, the OP has approved a list to be a valid input.

Explanation

lambda n:n[1:-1]    # Returns only the middle elements... pretty literal here
\$\endgroup\$
9
  • 1
    \$\begingroup\$ print input()[1:-1] is shorter \$\endgroup\$
    – user41805
    Commented Apr 2, 2017 at 14:36
  • \$\begingroup\$ Spring slicing sure is tricky \$\endgroup\$ Commented Apr 2, 2017 at 14:38
  • \$\begingroup\$ lambda n:n[1:-1] is even shorter \$\endgroup\$ Commented Apr 2, 2017 at 14:43
  • 1
    \$\begingroup\$ I may have tried with a wrong input. But when I tried, with Samantha Vee Hills as input in repl.it link that you've shared, this just prints amantha Vee Hill which is definitely not the output required. \$\endgroup\$ Commented Apr 2, 2017 at 14:46
  • 2
    \$\begingroup\$ Names will always have at least 2 space-separated parts is the first point of the question right. \$\endgroup\$ Commented Apr 2, 2017 at 14:47
1
\$\begingroup\$

C++, 91 bytes

#import<list>
#import<string>
void f(std::list<std::string>&n){n.pop_front();n.pop_back();}

Takes input as a reference to a list of strings and modifies the list directly.

Try it online!

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

APL (Dyalog), 8 6 bytes

¯1↓1↓⊢

Try it online!

This is a tacit train.

Explanation

When is a dyad, it returns all but the first/last n elements of its vector argument.

   1↓                  ⍝ Remove the first element in the 
     ⊢                 ⍝ right argument
¯1↓                    ⍝ and remove the last element
\$\endgroup\$
1
\$\begingroup\$

Bash, 31 19 bytes

echo ${@:2:$[$#-2]}

Try it online!

Breakdown:

Prints parameter expansion from second to second last element.

Edit

Removed commented code from breakdown section, since it's now just one line long.

-12 bytes thanks to Neil

\$\endgroup\$
4
  • \$\begingroup\$ Can you not just echo the expression in the first line directly? \$\endgroup\$
    – Neil
    Commented Apr 2, 2017 at 18:57
  • \$\begingroup\$ @Neil How can I do that, if the result of the expression is not $@? \$\endgroup\$ Commented Apr 2, 2017 at 19:13
  • \$\begingroup\$ Surely set -- assigns the result of the expression to $@? \$\endgroup\$
    – Neil
    Commented Apr 2, 2017 at 21:32
  • \$\begingroup\$ @Neil Took me way too long to understand what you mean. This is embarrasing... \$\endgroup\$ Commented Apr 2, 2017 at 23:26
1
\$\begingroup\$

CJam, 6 bytes

{1>W<}

Anonymous block that expects an array of strings on the stack, and leaves an array of strings after.

Try it online!

Explanation

1>    e# Slice the array after the first element
  W<  e# Slice the array before the last element
\$\endgroup\$
1
\$\begingroup\$

REXX, 42 bytes

arg a
say delword(delword(a,words(a)),1,1)
\$\endgroup\$
1
\$\begingroup\$

Ruby, 13 bytes

->s{s[1..-2]}

The author confirmed in comments that the input and output can be arrays.

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

Japt, 3 bytes

ůJ

Try it or run all test cases

\$\endgroup\$
2
  • \$\begingroup\$ Alternative: s1J \$\endgroup\$
    – Oliver
    Commented Dec 14, 2018 at 15:29
  • \$\begingroup\$ Oh, I posted an answer over a year ago. I'm gonna update it to s1J if you don't mind. \$\endgroup\$
    – Oliver
    Commented Dec 14, 2018 at 15:43
1
\$\begingroup\$

C (gcc), 144 139 91 86 bytes

y,z;char*f(char*s){for(y=0;*++s-32;);for(;s[y];y++)z=s[y]-32?z:y;z[s]=0;return!!*s+s;}

Try it online!

-48 bytes by learning C over the past year and a half since I first posted this

-7 bytes from Jonathan Frech

A function that takes in a char* and outputs a char* corresponding to the (character after the) first space in the string, but also edits the string so that it's last space is replaced with \0.

Note: this function will segfault if given a string without a space in it.

Full program:

y;z;char*f(char*s){y=0;while(*++s-32);while(s[y]){z=s[y]-32?z:y;y++;}s[z]=0;return s+!!*s;}
int main(int argc, char *argv[]){
	for (int i = 1; i < argc; ++i)
		printf("%s\n",f(argv[i]));
}

Un-golfed:

char *middle(char* name) {
	int index = 0, lastspace;
	while(name[0] != ' ') // move name pointer forward to the first space
		++name;
	while(name[index] != '\0') { // find the index in the (new) string of the last space
		if (name[index] == ' ') lastspace = index;
		index++;
	}
	name[lastspace] = '\0'; // Terminate the string at the last space
	if (name[0] == '\0') return name; // If the last space was the first space, return the empty string
	else return name + 1; // Else, return the new string
}

Try it online!

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

Perl 5 + -p040, 13 bytes

$_ x=$.>1&/ /

Try it online!

Explanation

With -p, input is implicitly stored in $_, the 040 flag makes space the line terminator which means the code is called for each word/name in the input. x= is the in-place string repetition operator which modifies the string in place (e.g. $_="abc";$_ x=3;# "abcabcabc") and the condition is $.>1 ($. is set to the current 'line' number, although since space is our line end character this is word/name number) &ed with / / (if $_ m//atches , which it will for all but the last word/name). Because of -p the result (the string repeated zero or one times depending on the conditional) is implicitly printed.

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

GolfScript, 6 bytes

~(;);`

Try it online!

Input is taken in the form of ["name""name""name"]. Input string is converted to an array, then the first and last elements are separated and discarded, and the result is formatted and outputted.

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

Pip -s, 8 bytes

@<@>Ya^s

Try it online!

-1 from DLosc.

\$\endgroup\$
2
  • \$\begingroup\$ 8 bytes, and you'll need the -s flag to handle cases with multiple middle names. If you take an array as input (using the -x flag--not available on TIO), you don't need the ^s and can therefore drop the Y. Or, if it's okay to take each of the name parts as a separate command-line argument (which is what you'd have if you typed them space-separated on the command line), you can use g instead of Ya^s. \$\endgroup\$
    – DLosc
    Commented Sep 11, 2021 at 23:06
  • \$\begingroup\$ Thanks! I'm keeping the 8byte version for now. \$\endgroup\$
    – Razetime
    Commented Sep 12, 2021 at 3:26
1
\$\begingroup\$

Dash, 24 bytes

g=\ ${*#* };echo ${g% *}

Try it online!

Input via args.

Also handles the unmentioned case of a single name being provided, returning nothing.

While this feels not that clever compared to the posted bash answer, that answer doesn’t work in Dash and this is the best I could muster within its restrictions.

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

Vyxal S, 2 bytes

ḢṪ

Try it Online!

Removes head and tail of list. S flag joins by spaces.

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

K (ngn/k), 25 24 bytes

{" "/*(1;-1+#t)_t:" "\x}

Try it online!

Down 1 byte by using assignment in expressions

Does the same thing as the APL answer.

Explanation:

{" "/*(1;-1+#t)_t:" "\x}    Main function. Takes x as input
                  " "\x     Split x by whitespace
                t:          Assign to variable t
      (       )_            Then delete the following elements in t:
       1;                   The first element, followed by
            #t              The length of t
         -1+                - 1
                            Delete returns back the string as an array, so we need to
     *                      Get the first element of the array
 " "/                       And joined each element in the sub-array by whitespace
                            This is to handle cases like "James Alfred Van Allen",
                            where the result after delete will be ["Alfred", "Van"]
\$\endgroup\$
1
\$\begingroup\$

Ruby -p, 20 bytes

Basically identical to Yelp’s sed answer and others.

gsub /^\S+ |\S+$/,""

Attempt This Online!

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

Go, 106 bytes

import."strings"
func f(s string)(o string){l:=Split(s," ")
if k:=len(l);k>2{o=Join(l[1:k-1]," ")}
return}

Attempt This Online!

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

Thunno 2 , 2 bytes

ḣṫ

Attempt This Online!

ḣ   # head remove
 ṫ  # tail remove
    # Ṡ flag joins by spaces
\$\endgroup\$
0
\$\begingroup\$

Batch, 70 bytes

@set s=.
:l
@if not "%3"=="" set s=%s% %2&shift&goto l
@echo(%s:~2%

The loop concatenates arguments starting with the second, shifting them until the third argument is empty. This results in a leading space, so to remove that I prepend with a . so that I can slice the string (slicing an empty string produces an erroneous result in Batch). If a trailing space on output is acceptable, then for 66 bytes:

@set s=
:l
@if not "%3"=="" set s=%s%%2 &shift&goto l
@echo(%s%
\$\endgroup\$
0
\$\begingroup\$

Ruby, 33 bytes

->s{$><<s.split[1..-2].join(' ')}
\$\endgroup\$
0
\$\begingroup\$

TI-Basic (TI-84 Plus CE), 131 bytes

Prompt Str0
inString(Str0," →A
length(Str0)–A→L
sub(Str0,A,L→Str0
" →Str2
For(B,1,L
sub(Str0,B,1)+Str2→Str2
End
inString(Str2," →A
L-A→L
sub(Str2,A,L→Str2
" →Str0
For(B,1,L
sub(Str2,B,1)+Str0→Str0
End
Disp Str0

Explanation:

Prompt Str0              # 4 bytes, input user string
inString(Str0," →A       # 10 bytes, store the index of the first space in A
length(Str0)–A→L         # 10 bytes, store the length of the string (after removing the first A characters) in L
sub(Str0,A,L→Str0        # 12 bytes, remove first A-1 and last characters of Str0
" →Str2                  # 6 bytes, temporary string to reverse Str0
For(B,1,L                # 7 bytes, reverse Str0 into Str2
sub(Str0,B,1)+Str2→Str2  # 16 bytes
End                      # 2 bytes
inString(Str2," →A       # 10 bytes, store the index of the first space in A
L-A→L                    # 6 bytes, get new length
sub(Str2,A,L→Str2        # 12 bytesremove first A-1 and last characters of Str2
" →Str0                  # 6 bytes, temporary string to reverse Str2
For(B,1,L                # 7 bytes, reverse Str2 into Str0
sub(Str2,B,1)+Str0→Str0  # 16 bytes
End                      # 2 bytes
Disp Str0                # 3 bytes, display final string with (2 trailing spaces)
\$\endgroup\$
0
\$\begingroup\$

Python 3, 28 bytes

print(input().split()[1:-1])

Try it online!

\$\endgroup\$

Your Answer

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