推送/弹出或者保存长度/尺寸?

推送/弹出或者保存长度/尺寸?

是否可以像 parindent 那样推送或弹出长度?我想暂时更改它,但很快就会重置它。

我有一个解决方案,但正在寻找更好的解决方案。我会将其作为答案发布。

答案1

您也可以不使用 LaTeX3,而是使用标记列表和一些宏来实现堆栈。其工作原理如下:

\documentclass{article}
\newtoks\paridstack
\paridstack={\empty}
\def\push#1#2{%
   \begingroup\toks0={{#1}}%
   \edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
}% push #1 onto #2
\def\pop#1{%
   \begingroup
   \edef\act{\endgroup\noexpand\splitList\the#1(tail)#1}\act
}% pop from #1
\def\splitList#1#2(tail)#3{%
   \ifx#1\empty Can't pop an empty stack.\else#1\global#3={#2}\fi
}
\begin{document}
  \noindent
  \push{200pt}{\paridstack}%
  \pop{\paridstack}\\
  \push{200pt}{\paridstack}%
  \push{300pt}{\paridstack}%
  \push{400pt}{\paridstack}%
  \pop{\paridstack}\\
  \pop{\paridstack}\\
  \pop{\paridstack}\\
  \pop{\paridstack}
\end{document}

它将打印200pt 400pt 300pt 200pt Can't pop from an empty stack.。当然,你可以用一些错误处理代码或要返回的某些默认值替换错误消息。这一切都基于第 14 章中的示例TeX 按主题分类。如果您想\parindent直接设置而不是只打印值,只需将的更改#1为。\else\splitList\parindent=#1

答案2

在你的序言中说,

\newlength{\savedparindent}

并且,当你想改变时\parindent,说

\setlength{\savedparindent}{\parindent}
\setlength{\parindent}{<dimen>}

然后你可以\parindent通过以下方式恢复之前的状态

\setlength{\parindent}{\savedparindent}

如果您使用环境结构,这甚至是不必要的:

\newenvironment{otherparindent}[1]
  {\par\setlength{\parindent}{#1}}
  {\par}

这样对 的更改\parindent就仅限于该环境。当然,没有必要使用这样的环境:你可以将代码放在\setlength{\parindent}{<dimen>}任何环境的定义中。

使用 LaTeX3 可以轻松获得基于堆栈的解决方案:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_uiy_parindent_seq

\NewDocumentCommand{\pushparindent}{m}
 {
  \seq_gpush:Nx \g_uiy_parindent_seq {\the\parindent}
  \dim_gset:Nn \parindent {#1}
 }
\NewDocumentCommand{\popparindent}{}
 {
  \seq_gpop:NN \g_uiy_parindent_seq \l_tmpa_tl
  \dim_gset:Nn \parindent {\l_tmpa_tl}
 }
\ExplSyntaxOff

\begin{document}

\showthe\parindent

\pushparindent{100pt}

\showthe\parindent

\pushparindent{50pt}

\showthe\parindent

\popparindent

\showthe\parindent

\popparindent

\showthe\parindent

\end{document}

这将依次显示 15.0pt、100.0pt、50.0pt、100.0pt、15.0pt;该命令\pushparindent存储当前值并设置\parindent为参数中指定的值。\popparindent您将获得最后存储的值。

以下是“标准 LaTeX”的版本:

\newtoks\parindentstack
\newcommand{\pushparindent}[1]{%
  \edef\temp{\noexpand\listelement{\the\parindent}\the\parindentstack}%
  \global\parindentstack=\expandafter{\temp}%
  \global\parindent=#1\relax
}
\newcommand{\popparindent}{%
  \if\relax\detokenize\expandafter{\the\parindentstack}\relax
    \errmessage{Empty stack}%
  \else
    \expandafter\getlistelement\the\parindentstack\getlistelement
  \fi
}
\def\getlistelement\listelement#1#2\getlistelement{%
  \global\parindentstack{#2}\global\parindent=#1\relax}

答案3

您可以创建一个新的宏长度并添加\parindent到它,从而创建\parindent

\newlength{\mylen}
\setlength\mylen{\parindent}
\setlength\parindent{0pt}

当您准备恢复时,\parindent您可以使用

\setlength\parindent{\mylen}

注意此方法不允许嵌套。

还有基于堆栈的解决方案,但效率可能较低。

使用 lualatex,您可以简单地使用 lua 中的堆栈和 tex 宏包装器。应该很容易理解。

答案4

此解决方案只是对 Roelof 的回应。我希望它在这里是合适的。我在他的解决方案\empty中用替换了\roelofstackbegin。这比使用 更安全\empty。Roelof 的堆栈看起来像一个万能堆栈。因此应避免任何可能的故障源。

\documentclass{article}
\makeatletter
\newtoks\roelofstack
\roelofstack={\roelofstackbegin}
\def\roelofstackbegin{\empty}
% push #1 onto #2:
\def\push#1#2{%
  \begingroup
  \toks0={{#1}}%
  \edef\act{\endgroup\global#2={\the\toks0 \the#2}}%
  \act
}
% pop from #1:
\def\pop#1{%
  \begingroup
  \edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}%
  \act
}
\def\SplitOff#1#2(tail)#3{%
  \ifx#1\roelofstackbegin
    \errhelp{Attempting to pop empty stack #3.}%
    \errmessage{You can't pop an empty stack.}%
  \else
    #1\global#3={#2}%
  \fi
}
\makeatother

% Tests:
\begin{document}
\noindent
\push{\empty}{\roelofstack}
\pop{\roelofstack}

\push{200pt}{\roelofstack}
\pop{\roelofstack}\par
\push{200pt}{\roelofstack}
\push{300pt}{\roelofstack}
\push{400pt}{\roelofstack}
\pop{\roelofstack}\par
\pop{\roelofstack}\par
\pop{\roelofstack}\par
% \pop{\roelofstack} % Popping empty stack.
\end{document}

相关内容