![TeX 容量超出,抱歉 [输入堆栈大小=5000]。使用宏中的 \label 命令](https://linux22.com/image/402463/TeX%20%E5%AE%B9%E9%87%8F%E8%B6%85%E5%87%BA%EF%BC%8C%E6%8A%B1%E6%AD%89%20%5B%E8%BE%93%E5%85%A5%E5%A0%86%E6%A0%88%E5%A4%A7%E5%B0%8F%3D5000%5D%E3%80%82%E4%BD%BF%E7%94%A8%E5%AE%8F%E4%B8%AD%E7%9A%84%20%5Clabel%20%E5%91%BD%E4%BB%A4.png)
我尝试编写一个宏,它必须根据输入参数放置一个或两个标签: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}