在调用 \csname ... \endcsname 之前删除非字母字符

在调用 \csname ... \endcsname 之前删除非字母字符

我有一篇很长的文章,其中提到了 500 多个科学名词,例如“麦克斯韦方程”。这些名词应该进入主索引,也应该出现在脚注中 - 但每章只能出现一次。我编写了一个宏,到目前为止,它完成了 90% 的工作。例如,我可以写

\eponym{le Chatelier}
\eponym{Le Chatelier}
\eponym{L e C h a t e l i e r}
\eponym{Le Chat'elier}
\eponym{Le Chat\'elier}

并定义命令序列 \@eChatelier 以使其保留当前章节号。第一行确实会产生脚注 - 其他行则不会 - 只要 \thechapter 不变。这很好。我面临的问题与使用外国口音有关。例如

\eponym{Le Chat{\'e}lier}

产生错误:

! Missing = inserted for \ifnum.
<to be read again> 
                   e
l.70  \eponym{Le Chat{\'e}lier}

我希望这个问题表述得合理。MWE 在这里:

\documentclass{report} 

\makeatletter

% Convert first letter in string to uppercase. 
% Then call \@tail on remaining string.

\def\@head#1{%
 \ifx\relax#1
 \else
  \ifnum \the\catcode`#1 = 11
%    \uppercase{#1}%          *** this line gives an error - I am not 100% sure why
%    #1%                     *** OK but makes eg "van der" different from "Van der"
   @%    *** removes the semantics problem above at the cost of introducing a hack!
  \else
  \fi
  \expandafter\@tail
 \fi
}

% Keep a-z, A-Z. 
% Ignore all other characters.

\def\@tail#1{%
 \ifx\relax#1
 \else
  \ifnum \the\catcode`#1 = 11
   #1%
  \else
  \fi
  \expandafter\@tail
 \fi
}

% To each eponym define a command sequence holding the chapter number.
% Print footonote.
% Do once-per-chapter only.
% Start over again when (if) the chapter counter is changed.

\newcommand{\eponym}[1]{%
 \edef\@@az{\@az{#1}}%                                           *** shortcut
 \ifcsname\@@az\endcsname%                              *** chapter 2, 3, etc
  \ifnum \thechapter > \csname\@@az\endcsname%        *** counter has changed
   \expandafter\edef\csname\@@az\endcsname{\thechapter}%
   {\sc #1}\expandafter\footnote{CSname: \@@az}%
  \else
   {\sc #1}%                                    *** same chapter as last time
  \fi
 \else%                                                    *** chapter 1 only
  \expandafter\edef\csname\@@az\endcsname{\thechapter}%
  {\sc #1}\expandafter\footnote{CSname: \@@az}%
 \fi
}

% Filter everything except a-z, A-Z from argument.
\def\@az#1{\@head #1\relax}

\makeatother

\begin{document} 

\section*{Chapter~\thechapter}

\eponym{le Chatelier}\\
\eponym{Le Chatelier}\\
\eponym{L e C h a t e l i e r}\\
\eponym{Le Chat'elier}\\
\eponym{Le Chat\'elier}\\
\eponym{Le Chat\' elier}\\
\eponym{Le Chat{\'e}lier}%                 *** this line gives an error - why?

\end{document}

答案1

使用更安全的 catcode 测试

  \ifcat a\noexpand#1%

使您的文档运行无错误,尽管{\'e}它不被视为与其他文档相同。无论如何,使用这样的括号是一种不好的标记样式,因为它会阻止字母之间应有的任何 kerns 连字符。但是,如果应该删除所有括号组,则可以添加。

如果您想要丢失括号组,那么在测试文件上只获取一个脚注标记,然后更改

\def\@tail#1{%

\def\@tail#1{\@@tail#1}

\def\@@tail#1{%

其中使用一个宏扩展级别来剥离一个括号组级别。

答案2

把脚注内容放在一边,专注于字符串操作,该stringstrings包可以简单地做到这一点:

\documentclass{report} 

\usepackage{stringstrings}

\begin{document} 

\section*{Chapter~\thechapter}

\newcommand\eponym[1]{%
  \noblanks[e]{#1}%
  \capitalize[e]{\thestring}%
  \alphabetic{\thestring}%
}

\eponym{le Chatelier}\\
\eponym{Le Chatelier}\\
\eponym{L e C h a t e l i e r}\\
\eponym{Le Chat'elier}\\
\eponym{Le Chat\'elier}\\
\eponym{Le Chat\' elier}\\
\eponym{Le Chat{\'e}lier}

\end{document}

答案3

我会用一种非常不同的方式来做:

\documentclass{report}
\usepackage[utf8]{inputenc}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\makeatletter
\NewDocumentCommand{\eponym}{m}
 {
  \tore_eponym:n { #1 }
 }
\cs_new_protected:Npn \tore_eponym:n #1
 {
  % A bit of LaTeX2: resolve commands into the LICR
  \protected@edef \l_tore_eponym_tl { #1 }
  %
  % Remove all non letters from the token list
  \regex_replace_all:nnN { [^A-Za-z]+ } { } \l_tore_eponym_tl
  % change the first letter with @
  \tl_set:Nx \l_tore_eponym_tl { @ \tl_tail:V \l_tore_eponym_tl }
  % print the argument
  \textsc{#1}
  % if the control sequence is not defined, define it and add a footnote
  \cs_if_exist:cF { \l_tore_eponym_tl }
   {
    \cs_set:cpx { \l_tore_eponym_tl } { \thechapter }
    \footnote{CSname:~\cs_to_str:c { \l_tore_eponym_tl } }
   }
 }
% A variant we need for printing the control sequence name
\cs_generate_variant:Nn \cs_to_str:N { c }
% The needed variable
\tl_new:N \l_tore_eponym_tl

\makeatother
\ExplSyntaxOff

\begin{document} 

\chapter{Abc}

\eponym{le Chatelier}\\
\eponym{Le Chatelier}\\
\eponym{L e C h a t e l i e r}\\
\eponym{Le Chat'elier}\\
\eponym{Le Chat\'elier}\\
\eponym{Le Chat\' elier}\\
\eponym{Le Chat{\'e}lier}\\
\eponym{Le Chatélier}

What chapter? Number \csname @eChatelier\endcsname
\end{document}

带有\protected@edef重音符号的字符,即使直接使用inputenc,也会被翻译成“扩展形式”,即 LICR。但是,诸如\ae或 之类的字母\o将被删除。可以将它们添加到例外列表中,并正确翻译成字母。

在此处输入图片描述

答案4

我的回答是否可以定义一个可扩展的命令来从其参数中删除控制序列?基本上解决了这个问题,目的基本相同。你可以看一下,尽管它不如其他基于包的答案那么精致。

相关内容