# Extract first word in a string

The title pretty much says it all, I need a command to get the first word in a string.

Based on this answer to another question of mine, I tried this:

\documentclass{article}

\makeatletter
\newcommand\FirstWord[1]{\@firstword#1 \@nil}%
\newcommand\@firstword{}%
\def\@firstword#1 #2\@nil{#1\unskip}%
\makeatother

\begin{document}
\FirstWord{John, Paul, George and Ringo}
\end{document}


It almost works, except for the fact it includes the comma. I get:

John,

While I want just:

John

So how can I do that?

PS: Ideally, if more than one word is inside braces, they should count as one. So \FirstWord{{John, Paul}, George and Ringo} should print "John, Paul".

• Please clarify what constitutes a (single) "word" for your purposes. In particular, does "Jean-Pierre" constitute a single word or is it composed of two words (connected by a hyphen)? Separately, does the search string always commence with a word, or could it start off with punctuation and other non-alphabetic characters? – Mico Jun 29 '16 at 7:14
• @Mico I'm working on a biblatex style and, when there's no author, entries should be cited using the first word in the title. If a book's title starts with a symbol, I guess ideally the command should ignore it. So what I need is something like... the first meaningful unit in the title that can stand on its own. But egreg's answer covers most cases, and for the exceptions the user can resort to fields like shorthand and shortauthor. 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
• I've gone ahead and posted a second LuaLaTeX-based solution. – Mico Jun 29 '16 at 16:27

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}

• Awesome! Just one thing… what if there's a period or a colon or a semicolon? I tried defining \@removeperiod, \@removecolon and so on, and adding one after the other in \def\@firstword, but I get "paragraph ended before \@removeperiod was complete". – dbmrq Jun 26 '16 at 20:41
• @danielbmarques You can add further tests for removing the undesired trailing character. – egreg Jun 26 '16 at 20:43

Thanks for comment by Mico, this is the suggested pattern to use. PS. I am not a pattern matching expert and do not play one on TV, but the nice thing about lualatex is one can employ sophisticated pattern matching procedures if they are needed.

\documentclass{article}
\usepackage{luacode} % for '\luaexec' and '\luastring' macros

\newcommand{\FirstWord}[1]{\luaexec{tex.print(string.match(\luastring{#1}, '\%w+\%-?\%w*'))}}

\begin{document}
\def\lst{John, Paul, George and Ringo}
\textbf{\FirstWord{\lst}} is the first word in \{\lst\}

\def\lst{-John, Paul, George and Ringo}
\textbf{\FirstWord{\lst}} is the first word in \{\lst\}

\def\lst{Marie-Claire, Paul, George and Ringo}
\textbf{\FirstWord{\lst}} is the first word in \{\lst\}

\end{document}


gives

Earlier version

lualatex solution

Updated with another variation of the call just for illustration.

\documentclass{article}
\usepackage{luacode}

\newcommand{\FirstWord}[1]{\luaexec{tex.print(string.match('#1', '([^,]+)'))}}

\begin{document}
\def\lst{John, Paul, George and Ringo}

\textbf{\FirstWord{\lst}} is the first word in \{\lst\}
\end{document}


The above does not handle special cases such as {{John, Paul}, George and Ringo}. It will still return John for the above.

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
function FirstWord(arg)
tex.print(string.match(arg, '([^,]+)'))
end
\end{luacode*}
\newcommand{\FirstWord}[1]{\directlua{FirstWord("#1")}}

\begin{document}
\def\lst{John, Paul, George and Ringo}

\textbf{\FirstWord{\lst}} is the first word in \{\lst\}

\end{document}


gives

• I've taken the liberty of making your \FirstWord macro more robust by writing \luastring{#1} instead of '#1'. (The latter bombs if the search string happens to contain a ' character.) – Mico Jun 29 '16 at 8:50

Admittedly a bit late to the game, but here's a second LuaLaTeX-based solution, which generalizes the earlier answer by @Nasser. This answer's pattern search algorithm satisfies the following criteria:

• If the string to be searched starts with a substring that's delimited by matching curly braces, the entire substring is returned.

• Otherwise, the first word is returned. Here, a "word" is taken to be either a collection of alphabetic characters -- e.g., "John" or "Nicolò" -- or a hyphenated pair of words -- e.g., "Kröller-Müller" and "Rhys-Davies". (Put differently, a hyphenated word is taken to be two single words that are joined by exactly one instance of -; the only restriction on the first word in the hyphenated pair is that it contain at least two characters.) Any non-alphabetic characters that precede the "word" in the full string are automatically discarded. The Lua code is unicode-aware, i.e., the words may contain non-ASCII alphabetic characters (such as ö, ü, and ò).

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{fontspec}
\usepackage{luacode} % for 'luacode' environment and '\luastring' macro
%% Lua-side code: A Lua function that does most of the work
\begin{luacode}
function fw ( s )
if string.find ( s , '^%b{}' ) then
first = string.sub ( string.match ( s , '%b{}' ), 2, -2 )
else
first = unicode.utf8.match ( s , '%w+%-?%w+' )
end
tex.sprint ( first )
end
\end{luacode}
%% TeX-side code: A macro that invokes the Lua function
\newcommand{\FW}[1]{\directlua{fw(\luastring{#1})}}

\begin{document}

\def\lst{{John and Paul} but not George or Ringo}
\FW{\lst}

\def\lst{'{Bay- Day} Hay}
\FW{\lst}

\def\lst{Kröller-Müller and Schwassmann-Wassmann}
\FW{\lst}

\end{document}