TeX 容量超出,抱歉 [输入堆栈大小=5000]。使用宏中的 \label 命令

TeX 容量超出,抱歉 [输入堆栈大小=5000]。使用宏中的 \label 命令

我尝试编写一个宏,它必须根据输入参数放置一个或两个标签:input=⟨⟩test1必须写一个标签:\label{sec:test1}

input=⟨⟩test1,test2必须写两个标签:\label{sec:test1}\label{test2}

对于一个标签来说还可以,但是对于两个标签来说,编译返回:

TeX capacity exceeded, sorry [input stack size=5000]. 
...bsection{Test}\ecriturelabel{test1,test2}

宏的写法如下:

\usepackage{xifthen}

\usepackage{xstring}

\newcommand{\ecriturelabel}[1]{

\ifthenelse{\isin{,}{#1}}{\def\labelone{sec:\StrBefore{#1}{,}}}{\def\labelone{sec:#1}}
\ifthenelse{\isin{,}{#1}}{\def\labeltwo{sec:\StrBehind{#1}{,}}}{\def\labeltwo{}}
\ifthenelse{\isin{,}{#1}}{\label{\labelone}\label{\labeltwo}}{\label{\labelone}}
}

答案1

据我所知,你想做

\ecriturelabel{a,b}

因此,这个问题\label{sec:a}\label{b},但\ecriturelabel{a}仅仅如此\label{sec:a}

这根本行不通\def\labelone{sec:\StrBefore{#1}{,}},因为\label需要一个完全可扩展的参数。

你可以更轻松地做到这一点:

\makeatletter
\newcommand{\ecriturelabel}[1]{%
  \def\el@perhaps{sec:}%
  \@for\next:=#1\do{\label{\el@perhaps\next}\def\el@perhaps{}}%
}
\makeatother

它将适用于参数中任意数量的逗号分隔的项\ecriturelabel

完整示例:

\documentclass{article}

\makeatletter
\newcommand{\ecriturelabel}[1]{%
  \def\el@perhaps{sec:}%
  \@for\next:=#1\do{\label{\el@perhaps\next}\def\el@perhaps{}}%
}
\makeatother

\begin{document}

\section{a}\ecriturelabel{a}

\section{bc}\ecriturelabel{b,c}

\end{document}

这是文件的内容.aux

\relax 
\@writefile{toc}{\contentsline {section}{\numberline {1}a}{1}\protected@file@percent }
\newlabel{sec:a}{{1}{1}}
\@writefile{toc}{\contentsline {section}{\numberline {2}bc}{1}\protected@file@percent }
\newlabel{sec:b}{{2}{1}}
\newlabel{c}{{2}{1}}

xparse使用和的更灵活的解决方案expl3

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\ecriturelabel}{O{sec}m}
 {
  \poulot_labels:nn { #1 } { #2 }
 }

\seq_new:N \l_poulot_labels_seq
\tl_new:N \l_poulot_label_first_tl

\cs_new_protected:Nn \poulot_labels:nn
 {
  \seq_set_from_clist:Nn \l_poulot_labels_seq { #2 }
  \seq_pop_left:NN \l_poulot_labels_seq \l_poulot_label_first_tl
  \label{#1:\l_poulot_label_first_tl}
  \seq_map_function:NN \l_poulot_labels_seq \label
 }
\ExplSyntaxOff

\newtheorem{theorem}{Theorem}

\begin{document}

\section{a}\ecriturelabel{a}

\section{bc}\ecriturelabel{b,c}

\begin{theorem}\ecriturelabel[theorem]{d,e}
Statement
\end{theorem}

\end{document}

文件.aux

\relax 
\@writefile{toc}{\contentsline {section}{\numberline {1}a}{1}\protected@file@percent }
\newlabel{sec:a}{{1}{1}}
\@writefile{toc}{\contentsline {section}{\numberline {2}bc}{1}\protected@file@percent }
\newlabel{sec:b}{{2}{1}}
\newlabel{c}{{2}{1}}
\newlabel{theorem:d}{{1}{1}}
\newlabel{e}{{1}{1}}

该命令有一个可选参数,用于将前缀添加到第一个标签。

这个想法是从给定的参数中形成一个项目序列;第一个项目被分离并生成带有前缀的标签;其余项目被\label逐一传递。

答案2

引用 xstring 包的手册:

3.2 宏的扩展,可选参数

此包的宏不是纯粹可扩展的,即它们不能放在 的参数中\edef。嵌套宏也是不可能的。

因此,所有返回结果的宏(即除测试之外的所有宏)在最后位置都有一个可选参数。语法是,其中是将接收宏结果的控制序列的名称:使用 进行赋值,这使得宏的结果完全可扩展。当然,如果存在可选参数,则宏不会显示任何内容。[⟨name⟩][⟨name⟩]\edef[⟨name⟩]

因此,这种结构是不允许的,应该分配给:\Result左边的4个字符, 相当于:xstring
\edef\Result{\StrLeft{xstring}{4}}

\StrLeft{xstring}{4}[\Result]

并且这个嵌套结构也不允许,它应该删除 \StrGobbleLeft{\StrGobbleRight{xstring}{1}}{1}xstring的第一个和最后一个字符 ,应该像这样写:


\StrGobbleRight{xstring}{1}[\mystring]
\StrGobbleleft{\mystring}{1}

不完全可扩展不仅意味着事物不能放入 的“参数”中\edef。它还意味着事物通常不能在完全扩展上下文中使用,这意味着它们也不能放入\label-command 的参数中。

也许下面的方法会有所帮助:

\documentclass{article}

\usepackage{xifthen}
\usepackage{xstring}

\newcommand{\ecriturelabel}[1]{%
  \ifthenelse{\isin{,}{#1}}{%
    \StrBefore{#1}{,}[\labelname]%
    \label{sec:\labelname}%
    \StrBehind{#1}{,}[\labelname]%
    \label{\labelname}%
  }{%
    \label{sec:#1}%
  }%
}%

\begin{document}

\section{Test}

\subsection{Test}

\ecriturelabel{test1,test2}

\noindent\ref{sec:test1}

\noindent\ref{test2}

\end{document}

上述代码没有考虑多个逗号的情况,也没有考虑标签逗号列表元素周围空格的情况,也没有考虑诸如、\ecriturelabel{,}等情况。\ecriturelabel{test1,}\ecriturelabel{,test2}

相关内容