# Collapse index sub-items on to the parent line

I have a long document with lots of index entries defined like \index{Surname!Name}, and I've decided that for one particular purpose, I would like the index formatted as if I had written \index{Surname, Name} throughout, but I don't particularly want to edit each use of the \index. Is there a strategy for doing this? In case it's relevant, I'm using imakeidx and XeLaTeX.

I don't think a MWE really adds anything, but it seems to be expected all the same:

\documentclass{article}
\usepackage{imakeidx}
\usepackage[columns=1]{idxlayout}
\makeindex
\begin{document}
John\index{Smith!John} and William Smith\index{Smith!William}
were brothers.  Jack Jones\index{Jones!Jack} is another person.
\printindex
\end{document}


What I want is for the index to read

Jones, Jack, 1
Smith, John, 1
Smith, William, 1

Update: See the shorter version at the end of the answer.

Perhaps it is possible to play with catcodes or to change the \indexentry command, another way is to use l3regex and replace the ! with ,, by a small redefinition of the \index command.

\documentclass{article}
\usepackage{xparse}
\usepackage{l3regex}

\usepackage{imakeidx}
\usepackage[columns=1]{idxlayout}
\usepackage{letltxmacro}

\ExplSyntaxOn
\AtBeginDocument{%
\LetLtxMacro\idxorig\index

\RenewDocumentCommand{\index}{o+m}{%
\tl_set:Nn \l_tmpa_tl {#2} % Store the index entry
\regex_replace_once:nnN {!}{,\~} \l_tmpa_tl % replacing
\IfValueTF{#1}{%
\idxorig[#1]{\tl_use:N \l_tmpa_tl} % write the new index entry
}{
\idxorig{\tl_use:N \l_tmpa_tl}% write the new index entry
}
}
}
\ExplSyntaxOff

\makeindex

\begin{document}
John\index{Smith!John} and William Smith\index{Smith!William}
were brothers.  Jack Jones\index{Jones!Jack} is another person.
\printindex
\end{document}


Update with the shorter version (as egreg suggested)

\documentclass{article}

\usepackage{imakeidx}
\usepackage[columns=1]{idxlayout}
\usepackage{letltxmacro}

\usepackage{xparse}

\ExplSyntaxOn
\AtBeginDocument{%
\LetLtxMacro\idxorig\index

\RenewDocumentCommand{\index}{o+m}{%
\tl_set:Nn \l_tmpa_tl {#2}
\tl_replace_once:Nnn \l_tmpa_tl  {!}{,\ }
\IfValueTF{#1}{%
\idxorig[#1]{\tl_use:N \l_tmpa_tl}
}{
\idxorig{\tl_use:N \l_tmpa_tl}
}%
}
}
\ExplSyntaxOff

\makeindex

\begin{document}
John\index{Smith!John} and William Smith\index{Smith!William}
were brothers.  Jack Jones\index{Jones!Jack} is another person.
\printindex
\end{document}

• \tl_replace_once:Nnn seems easier here. – egreg Jan 15 '17 at 10:49
• Anyway, I'd use {,\ } (backslash space) in the replacement string. Not a big deal anyway. With \tl_replace_once:Nnn it would be \tl_replace_once:Nnn \l_tmpa_tl { ! } { ,~ } – egreg Jan 15 '17 at 10:59
• @egreg: I always forgot about \tl_replace_once:Nnn -- I will change later on. Thanks for suggestion – user31729 Jan 15 '17 at 11:20
• Thanks. I've accepted the solution (and +1'd it), but I can't help but think fiddling with the parser is the wrong solution, and a redefinition of \item and \subitem would be better. But I can't see how to do that simply, and your solution is nice and short. – richard Jan 15 '17 at 21:44
• @richard: You still have to 'parse' the '!' content away from being fed into item. Please consider that in fact makeindex generates the .ind file, not LaTeX – user31729 Jan 15 '17 at 21:59