You're almost there, just remove the trailing comma
\documentclass{article}
\makeatletter
\newcommand\FirstWord[1]{\@firstword#1 \@nil}%
\newcommand\@firstword{}%
\newcommand\@removecomma{}%
\def\@firstword#1 #2\@nil{\@removecomma#1,\@nil}%
\def\@removecomma#1,#2\@nil{#1}
\makeatother
\begin{document}
X\FirstWord{John, Paul, George and Ringo}X
X\FirstWord{John}X
X\FirstWord{John and Paul}X
X\FirstWord{{John, Paul}, George and Ringo}X
\end{document}

You can add further tests for removing other delimiters
\documentclass{article}
\makeatletter
\newcommand\FirstWord[1]{\@firstword#1 \@nil}%
\def\@firstword#1 #2\@nil{\@removecomma#1,\@nil}%
\def\@removecomma#1,#2\@nil{\@removeperiod#1.\@nil}
\def\@removeperiod#1.#2\@nil{\@removesemicolon#1;\@nil}
\def\@removesemicolon#1;#2\@nil{#1}
\makeatother
\begin{document}
X\FirstWord{John; Paul; George; Ringo}X
X\FirstWord{John. Paul. George. Ringo}X
X\FirstWord{John}X
X\FirstWord{John and Paul}X
X\FirstWord{{John. Paul}. George. Ringo}X
\end{document}
If you don't need expandability, you can use l3regex:
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\FirstWord}{m}
{
% split the argument at spaces
\seq_set_split:Nnn \l_tmpa_seq { ~ } { #1 }
% get the first item
\tl_set:Nx \l_tmpa_tl { \seq_item:Nn \l_tmpa_seq { 1 } }
% remove a trailing period, semicolon or comma (\Z matches the end)
\regex_replace_once:nnN { [.;,]\Z } { } \l_tmpa_tl
% output the result
\tl_use:N \l_tmpa_tl
}
\ExplSyntaxOff
\begin{document}
X\FirstWord{John, Paul, George and Ringo}X
X\FirstWord{John; Paul; George; Ringo}X
X\FirstWord{John. Paul. George. Ringo}X
X\FirstWord{John}X
X\FirstWord{John and Paul}X
X\FirstWord{{John, Paul}, George and Ringo}X
X\FirstWord{{John. Paul}. George. Ringo}X
\end{document}
shorthandandshortauthor. Besides, I can't force possible users to use lualatex. So I'm going with his code, even though the lua option is really cool. :) – dbmrq Jun 29 '16 at 10:20