我想使用包中的\IfSubStr
和宏,有条件地将出现在较长字符串中的字符串加粗。我遇到的问题与宏的扩展有关,这取决于和宏的工作。我怎样才能让宏正常工作?\StrSubstitute
xstring
\makebold
\surnamefirst
\surnamelast
\makebold
\documentclass{article}
\usepackage{xstring}
\newcommand{\name}{John Doe}
\makeatletter
% Macro to extract and store "last name" from full-name string
\newcommand{\lastname}{%
\IfSubStr{\name}{.}%
{\StrBehind{\name}{. }}%
{\StrBehind{\name}{ }}%
[\@lastname]
}
% Extract and store first name from full-name string
\newcommand{\firstname}{%
\StrBefore{\name}{ }[\@firstname]
}
% Extract first initial from full-name string
\newcommand{\firstinitial}{%
\StrLeft{\name}{1}[\@firstinitial]
}
% Extract middle initial (if any) from full-name string
\newcommand{\middleinitial}{%
\StrBetween{\name}{ }{.}[\@middleinitial]
}
\newcommand{\testxstring}{%
\middleinitial % Find middle initial
\IfStrEq{\@middleinitial}{}%
{No middle initial!}%
{Middle initial: \@middleinitial}
}
% Surname first
\newcommand{\surnamefirst}{%
\firstinitial
\middleinitial % Find middle initial
\lastname
\IfStrEq{\@middleinitial}{}%
{\@lastname, \@firstinitial.}%
{\@lastname, \@firstinitial.~\@middleinitial.}
}
% Surname last
\newcommand{\surnamelast}{%
\firstinitial
\middleinitial % Find middle initial
\lastname
\IfStrEq{\@middleinitial}{}%
{\@firstinitial.~\@lastname}%
{\@firstinitial.~\@middleinitial.~\@lastname}
}
% Render full name in bold
\newcommand{\makeboldname}[1]{%
\expandarg
\IfSubStr{#1}{\getvalue{name}}%
{\StrSubstitute{#1}{\name}{\textbf{\name}}\par}%
{#1}
}
% Render only last name in bold
\newcommand{\makeboldlastname}[1]{%
\lastname
\expandarg
\IfSubStr{#1}{\@lastname}%
{\StrSubstitute{#1}{\@lastname}{\textbf{\@lastname}}\par}%
{#1}
}
% Render surname-first and surname-last in bold
\newcommand{\makebold}[1]{%
\expandarg
\IfSubStr{#1}{\surnamefirst}%
{\StrSubstitute{#1}{\surnamefirst}{\textbf{\surnamefirst}}\par}%
{\IfSubStr{#1}{\surnamelast}%
{\StrSubstitute{#1}{\surnamelast}{\textbf{\surnamelast}}\par}%
{#1}%
}
}
\makeatother
\begin{document}
\name
\surnamefirst
\surnamelast
\makeboldname{His name was John Doe.}
\makeboldlastname{Again, Doe was his last name.}
\makebold{I heard that Doe, J. was from Kentucky.}
\makebold{There was also a J. Doe from New York.}
\end{document}
预期输出:
约翰·多伊
多伊,J.
J·多伊
他以前的名字是约翰·多伊。
再次,多伊是他的姓氏。
我听说多伊,J.来自肯塔基州。
还有J·多伊来自纽约。
答案1
这似乎是正则表达式的工作:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\definename}{m}
{
\adam_name_define:n { #1 }
}
\NewDocumentCommand{\makebold}{m}
{
\adam_name_makebold:n { #1 }
}
\NewDocumentCommand{\makeboldlastname}{m}
{
\adam_name_makebold_lastname:n { #1 }
}
\tl_new:N \l_adam_name_full_tl
\tl_new:N \l_adam_name_first_tl
\tl_new:N \l_adam_name_last_tl
\tl_new:N \l_adam_name_initials_tl
\tl_new:N \l__adam_name_input_tl
\cs_new_protected:Nn \adam_name_define:n
{
% store the full name
\tl_set:Nn \l_adam_name_full_tl { #1 }
% duplicate it in two token lists to be modified
\tl_set_eq:NN \l_adam_name_first_tl \l_adam_name_full_tl
\tl_set_eq:NN \l_adam_name_last_tl \l_adam_name_full_tl
% remove everything from the last space to the end (first name)
\regex_replace_once:nnN { (.*)\s[^\s]*\Z } { \1 } \l_adam_name_first_tl
% remove everything up to the last space (surname)
\regex_replace_once:nnN { .*\s([^\s]*)\Z } { \1 } \l_adam_name_last_tl
% duplicate the token list with the first name
\tl_set_eq:NN \l_adam_name_initials_tl \l_adam_name_first_tl
% remove letters after the first in the first name part, replacing them with a period (initials)
\regex_replace_all:nnN { ([[:alpha:]])[[:alpha:]]+ } { \1. } \l_adam_name_initials_tl
}
\cs_new_protected:Nn \adam_name_makebold:n
{
\tl_set:Nn \l__adam_name_input_tl { #1 }
% \u{<token list name>} stands for the contents of the token list
% we'll search for “full name” or “initials surname” or
% “surname, first name” or “surname, initials”
% and replace the match with \textbf{\match}
\regex_replace_once:nnN
{
(
\u{l_adam_name_full_tl} % name surname
|
\u{l_adam_name_initials_tl} \s \u{l_adam_name_last_tl} % initials surname
|
\u{l_adam_name_last_tl} , \s \u{l_adam_name_first_tl} % surname, name
|
\u{l_adam_name_last_tl} , \s \u{l_adam_name_initials_tl} % surname, initials
)
}
{ \c{textbf} \cB\{ \1 \cE\} }
\l__adam_name_input_tl
% print
\tl_use:N \l__adam_name_input_tl
}
\cs_new_protected:Nn \adam_name_makebold_lastname:n
{
\tl_set:Nn \l__adam_name_input_tl { #1 }
% search for the surname and replace it with \textbf{<match>}
\regex_replace_once:nnN
{ (\u{l_adam_name_last_tl}) }
{ \c{textbf} \cB\{ \1 \cE\} }
\l__adam_name_input_tl
\tl_use:N \l__adam_name_input_tl
}
\ExplSyntaxOff
\begin{document}
\definename{John Doe}
\makebold{His name was John Doe.}
\makebold{His name was J. Doe.}
\makebold{His name was Doe, John.}
\makebold{His name was Doe, J. again.}
\makeboldlastname{Again, Doe was his last name.}
\definename{John T. Doe}
\makebold{His name was John T. Doe.}
\makebold{His name was J. T. Doe.}
\makebold{His name was Doe, John T. again.}
\makebold{His name was Doe, J. T. again.}
\makeboldlastname{Again, Doe was his last name.}
\end{document}
答案2
xstring
正如承诺的那样,下面是其作者 Christian Tellechea给出的答案。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xstring}
\def\makebold#1#2{%
\begingroup\expandarg
\StrCount{#1}{ }[\nbspaces]%
\StrCut[\nbspaces]{#1}{ }\firstname\lastname
\StrSplit\firstname1\firstnameinitial\fisrtnameremain
\IfSubStr\fisrtnameremain{ }
{\StrBehind\fisrtnameremain{ }[\fisrtnameremain]}
{\let\fisrtnameremain\empty}%
\edef\firstnameinitial{\firstnameinitial.\ifx\fisrtnameremain\empty\else\space\fi\fisrtnameremain}%
\edef\stringA{#1}%
\edef\stringB{\firstnameinitial\space\lastname}%
\edef\stringC{\lastname, \firstname}%
\edef\stringD{\lastname, \firstnameinitial}%
\StrSubstitute{#2}\stringA{\expandafter\textbf\expandafter{\stringA}}[\finaltext]%
\StrSubstitute\finaltext\stringB{\expandafter\textbf\expandafter{\stringB}}[\finaltext]%
\StrSubstitute\finaltext\stringC{\expandafter\textbf\expandafter{\stringC}}[\finaltext]%
\StrSubstitute\finaltext\stringD{\expandafter\textbf\expandafter{\stringD}}[\finaltext]%
\StrSubstitute\finaltext\lastname{\expandafter\textbf\expandafter{\lastname}}[\finaltext]%
\finaltext
\endgroup
}
\begin{document}
\makebold{John Doe}{His name was John Doe.}
\makebold{John Doe}{His name was J. Doe.}
\makebold{John Doe}{His name was Doe, John.}
\makebold{John Doe}{Again, Doe was his last name.}
\bigskip
\makebold{John T. Doe}{His name was John T. Doe.}
\makebold{John T. Doe}{His name was J. T. Doe.}
\makebold{John T. Doe}{His name was Doe, John T. again.}
\makebold{John T. Doe}{His name was Doe, J. T. again.}
\makebold{John T. Doe}{Again, Doe was his last name.}
\end{document}
输出结果与预期一致。虽然正则表达式更通用,但它确实不那么冗长。