36
\$\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\$ Apr 2 '17 at 14:34
  • 5
    \$\begingroup\$ If other formats than a space-separated string are allowed, please edit that into the specification. \$\endgroup\$ Apr 2 '17 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
    Apr 2 '17 at 15:17
  • 3
    \$\begingroup\$ Are leading spaces allowed? \$\endgroup\$
    – betseg
    Apr 2 '17 at 15:32
  • 4
    \$\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\$ Apr 3 '17 at 2:16

68 Answers 68

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\$ Apr 2 '17 at 16:26
  • \$\begingroup\$ You can't use nnz on a cell array, but I did the other two changes :) \$\endgroup\$ Apr 2 '17 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
    Apr 3 '17 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\$ Apr 3 '17 at 20:10
  • \$\begingroup\$ I'm receiving the following error when compiling with Visual Studio 2012:error C2100: illegal indirection \$\endgroup\$ Apr 5 '17 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
    Apr 5 '17 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\$ Dec 14 '18 at 16:50
  • \$\begingroup\$ @JonathanFrech it leads to "RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:221)" without space \$\endgroup\$
    – bbb1
    Dec 14 '18 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
    Dec 14 '18 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\$ Dec 14 '18 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\$

Factor, 17 bytes

[ rest but-last ]

Try it online!

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.
  • but-last Take all elements of a sequence but the last.
\$\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
    Sep 11 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
    Sep 11 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
    Sep 11 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
    Sep 11 at 18:23
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
    Apr 2 '17 at 14:36
  • \$\begingroup\$ Spring slicing sure is tricky \$\endgroup\$ Apr 2 '17 at 14:38
  • \$\begingroup\$ lambda n:n[1:-1] is even shorter \$\endgroup\$ Apr 2 '17 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\$ Apr 2 '17 at 14:46
  • 2
    \$\begingroup\$ Names will always have at least 2 space-separated parts is the first point of the question right. \$\endgroup\$ Apr 2 '17 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
    Apr 2 '17 at 18:57
  • \$\begingroup\$ @Neil How can I do that, if the result of the expression is not $@? \$\endgroup\$ Apr 2 '17 at 19:13
  • \$\begingroup\$ Surely set -- assigns the result of the expression to $@? \$\endgroup\$
    – Neil
    Apr 2 '17 at 21:32
  • \$\begingroup\$ @Neil Took me way too long to understand what you mean. This is embarrasing... \$\endgroup\$ Apr 2 '17 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
    Dec 14 '18 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
    Dec 14 '18 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
    Sep 11 at 23:06
  • \$\begingroup\$ Thanks! I'm keeping the 8byte version for now. \$\endgroup\$
    – Razetime
    Sep 12 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.

New contributor
bxm is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\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\$
0
\$\begingroup\$

Ruby, 17 bytes

$><<$*[1..-2]*' '

Full program, takes input as command line arguments, e.g.:

$ ruby middle.rb john jacob jingleheimer shmidt
jacob jingleheimer

If we don't mind having the result wrapped in quotation marks, can just use:

p$*[1..-2]*' '
$ ruby middle2.rb john jacob jingleheimer shmidt
"jacob jingleheimer"

Of course, we can also just take a list and return a list, which can be as short as a 13 byte lambda.

->s{s[1..-2]}
# usage:
y = ->s{s[1..-2]};
y.call ["john","jacob","jingleheimer","shmidt"] #=> ["jacob", "jingleheimer"]
\$\endgroup\$
0
\$\begingroup\$

Sed, 23 20 bytes

s/\w* (.*) \w*$/\1/

Unlike my last sed entry which involved a pipeline from one sed command to another, this one is just a simple, single command, so I'm only counting the bytes of the sed script.

Edited: Plus a 1-byte penalty for the -r flag. Thank you, Krixti Lithos, for pointing that out!

\$\endgroup\$
4
  • \$\begingroup\$ Can you use the -r flag to save some bytes from escaping the groups? \$\endgroup\$
    – user41805
    Apr 3 '17 at 8:22
  • \$\begingroup\$ @Kritixi I could but I'm not sure how to score that. Does it count as 2 bytes for the -r flag or only 1 byte? \$\endgroup\$ Apr 4 '17 at 5:37
  • \$\begingroup\$ It counts as only 1 byte \$\endgroup\$
    – user41805
    Apr 4 '17 at 5:39
  • \$\begingroup\$ @Kritixi Thanks! I just found this answer on meta, too. And I see another change I can make to improve it as well. \$\endgroup\$ Apr 4 '17 at 5:44
0
\$\begingroup\$

Pushy, 17 bytes

32K-$.;@$.;.@32+"

Try it online!

32 K-    \ Take away 32 from every character.
         \ Now we have the value 0 where there were spaces.
$        \ Until we reach a zero:
 .;      \   Pop a character from the end
         \ Everything after the last space is now removed
@        \ Reverse stack
$.;      \ Do the same
.        \ Pop the leading space
32+      \ Add 32 to everything to map the numbers back to their original characters
@"       \ Reverse and print

This is the first method I thought of, and looks like the shortest.

\$\endgroup\$
0
\$\begingroup\$

C#, 72 69 bytes

Takes a string, returns a string...

s=>string.Join(" ",s.Split(' ').Skip(1).TakeWhile(n=>!s.EndsWith(n)))

C# 43 bytes

Takes a string array, returns a string array...

s=>s.Skip(1).TakeWhile((n,i)=>i<s.Length-2)
\$\endgroup\$
0
\$\begingroup\$

c, 72 bytes

g(char*p){char*e,*s=0;for(;*p;p++)*p-32?0:s?(e=p):(s=p);*e=0;puts(s+1);}

Try it online

\$\endgroup\$
0
\$\begingroup\$

Clojure, 107 bytes

(fn[f](clojure.string/join" "(map #(apply str %)(drop 1(drop-last(take-nth 2(partition-by #(= % \ )f)))))))

Unfortunately drop/drop-last was shorter than subvec.

(defn middle-name [full-name]
  ; Partition the string into a list of names split on spaces, then take every second element
  ;  since partition keeps the spaces 
  (let [sub-names (take-nth 2
                    (partition-by #(= % \ ) full-name))]

    ; ... then join the middle names together on a space.
    (clojure.string/join " "
      ; Drop returns list of chars, so turn them back into strings...
      (map #(apply str %)
           ; Drop the first and last name
           (drop 1
             (drop-last sub-names))))))
\$\endgroup\$

Your Answer

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