从输入中自动解析/提取单参数命令(用于新环境)?

从输入中自动解析/提取单参数命令(用于新环境)?

我不确定这在原则上是否可行,所以让我尝试解释一下;考虑这个 MWE:

\documentclass{article}

\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikzpagenodes} % current page text area
\usepackage{caption}
\pagecolor{yellow!15}

% convert rose: -resize 400x200! /tmp/test.png # ImageMagick

\begin{document}

  \begin{center}                    % {figure}[h!]
  \centering                        % %(for figure)
  \includegraphics[width=1.0\textwidth]{/tmp/test.png}
  \captionof{figure}[shortdesc]{    % \caption[shortdesc]{
  caption lorem ipsum dolor sit amet, text line 01
  caption consectetur adipisicing elit text line 02
  caption text line 03
  }
  \label{fig:test1}
  \end{center}                      % {figure}
  % \end

  % https://tex.stackexchange.com/questions/14512/how-to-define-a-figure-size-so-that-it-consumes-the-rest-of-a-page/14514#14514
  % needs texing twice:
  \begin{tikzpicture}[overlay,remember picture]
    % Caption
    \node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
      \captionof{figure}[shortdesc]{ %
      caption lorem ipsum dolor sit amet, text line 01
      caption consectetur adipisicing elit text line 02
      caption text line 03
      }%
      \label{fig:test2} % has to stand after the caption, to get its number
    };
    % Image
    \path let \p0 = (0,0), \p1 = (caption.north) in
      node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
        \pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
        \includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
    };
  \end{tikzpicture}%

\end{document}

第一个图像片段是我常用的模式{figure}(或{center},表示非浮动)和\includegraphics。不过,偶尔我必须让图像适合页面底部,为此我会使用模式tikz,按照如何定义图形大小以使其占据页面的剩余部分?- 这是第二幅图像片段。

现在,当我等待文档编译一分钟,意识到图片不在我想要的位置时,我总是非常沮丧,“也许 \vspace{-1em} 会有帮助”?,编译,等待,“不...也许 \clearpage”?......等等,直到我意识到我必须使用 tikz 模式 - 这现在需要我重新排列代码片段:/

我喜欢我的典型模式,因为它的内容基本上只是这三个命令 - 以及它们的(唯一)参数:

\includegraphics[width=1.0\textwidth]{/tmp/test.png}
\captionof{figure}[shortdesc]{    % \caption[shortdesc]{
  caption lorem ipsum dolor sit amet, text line 01
  caption consectetur adipisicing elit text line 02
  caption text line 03
}
\label{fig:test1}

...然后,我基本上可以只交换{figure}{center}和),而不用caption\captionof这些内部结构进行太多改变。

因此,我最终想要做的是定义一个新的环境,比如说{tikzbottomfigure},这样我就可以写入相同的模式:

\begin{tikzbottomfigure}
  \includegraphics[width=1.0\textwidth]{/tmp/test.png}
  \captionof{figure}[shortdesc]{    % \caption[shortdesc]{
    caption lorem ipsum dolor sit amet, text line 01
    caption consectetur adipisicing elit text line 02
    caption text line 03
  }
  \label{fig:test1}
\end{tikzbottomfigure}

... - 这是我不确定的部分 - 我希望新的环境代码自动将第一个命令\includegraphics...及其参数(所有直到第二个命令)提取到#1;将第二个命令\captionof...及其内容提取到#2;并将\label及其内容提取到#3- 以便在新的环境定义代码中,我可以简单地写道:

\begin{tikzpicture}[overlay,remember picture]
  % Caption
  \node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
    #2%
    #3% has to stand after the caption, to get its number
  };
  % Image
  \path let \p0 = (0,0), \p1 = (caption.north) in
    node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
      \pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
      #1%
  };
\end{tikzpicture}%

暂时让我们忽略\includegraphics两种情况下没有相同参数的潜在问题;我的主要动机是避免定义具有多个参数的新环境,这将迫使我使用括号来分隔参数 - 并最终迫使我再次重写图像代码片段,而这正是我首先想要避免的。

我认为唯一可行的方法是,是否存在一种机制,可以从一段文本中解析/拆分并提取“命令及其参数”(并可能#1稍后将它们分配给各个类型参数);值得注意的是,某些命令可能跨越多行文本,因此这不应该只是一个 (ASCII) 文本行拆分器。所以,最终,我的问题是 - Latex 中是否存在这样的解析机制,以便我可以将其应用于我所描述的预期用途?

答案1

tikzbottomfigure好吧,我想我已经找到了一些线索,所以我将发布这个(MWE,包括一些评论和链接,如下) -按要求实现的。

问题是,由于我们要提取的命令是单独的标记——我们可以使用 a 中的参数定义在\def标记处进行拆分;所以我们得到了我们的“解析\def”函数(这里称为\splitfigurepattern)。这里的一个问题是,拆分的内容可能仍包含命令,这些命令可能想要在解析中执行\def。因此,我们在解析中使用的任何 \defs 都\def应该是 (eTex) \protected——但当我们想要返回我们提取的数据时,这会迫使我们做一些\expandafter体力活。

第二个问题是,在典型的 中,我们无法真正捕获环境的和 之间\newenvironment的内容- 因为这通常会引入不平衡的括号。因此,我们必须使用包中的,然后包会将环境中的内容提供为,我们可以将其用于解析器函数。\begin{}\end{}\NewEnvironenviron\BODY\def

买者自慎 - 请注意,如果环境中的内容最终以某种方式不是匹配解析的输入参数定义\def,那么 Latex 将因“失控参数”而崩溃;所以 YMMV。

以下是 MWE 代码:

\documentclass{article}

\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikzpagenodes} % current page text area
\usepackage{caption}
\usepackage{environ} % \BODY
% \usepackage{trace}
\pagecolor{yellow!15}

% convert rose: -resize 400x200! /tmp/test.png

% (c0)
% (c1)

% this one splits entire figure pattern, containing:
% \includegraphics[...]...\captionof...\label...
% (no need for external split call, as in (c1))
% still using protected, since arbitrary commands can appear wherever inside..
%\def\splitfigurepattern\includegraphics[#1]#2\captionof#3\label#4{%
% include #1 before \incl.graphics (to handle if a \centering there):
\def\splitfigurepattern#1\includegraphics[#2]#3\captionof#4\label#5{%
  \protected\def\sfpA{#2} % 'width=1.0\textwidth '
  \protected\def\sfpB{#3} % '{/tmp/test.png}'
  \protected\def\sfpC{#4} % '{figure}[shortdesc]{ caption lorem...03 }'
  \protected\def\sfpD{#5} % 'fig:test1'
  \protected\def\sfpO{#1} % '' if empty before \inclgr.; else '\centering'
  \typeout{sfp A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC^^J D: \meaning\sfpD^^J O: \meaning\sfpO} %
}
\def\runsplitfp#1{\splitfigurepattern#1\relax}

% (c2)

\NewEnviron{tikzbottomfigure}{%
  % call parser to split the argument
  % \expandafter\runsplitfp\BODY% ! Use of \splitfigurepattern doesn't match its definition.
  \expandafter\expandafter\runsplitfp{\BODY}% passes!
  %
  % here we should have parsed elements - proceed to output tikz code:
  % http://tex.stackexchange.com/questions/14512/how-to-define-/14514#14514
  % needs texing twice:
  \begin{tikzpicture}[overlay,remember picture]
    % Caption
    % unless expanded properly, \label{\tmpD} will
    % fail with: "! Undefined control sequence. \sfpD"
    %\edef\tmpD{\sfpD}                                    % tmpD: \sfpD
    \expandafter\edef\expandafter\tmpD\expandafter{\sfpD} % tmpD: fig:test2
    \typeout{tmpD: \tmpD}
    \node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
      \expandafter\captionof\sfpC
      \label{\tmpD} %
    };
    % Image
    \expandafter\edef\expandafter\tmpB\expandafter{\sfpB} % better: File `{/tmp/test.png} ' not found.
    \expandafter\edef\expandafter\tmpBB\tmpB \typeout{BB \tmpBB}% ok: BB /tmp/test.png
    \path let \p0 = (0,0), \p1 = (caption.north) in
      node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
        \pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
        % (c3)
        \expandafter\includegraphics\expandafter[\sfpA,height=\imgheight pt,
keepaspectratio,]{\tmpBB}%
    };
  \end{tikzpicture}%
} % \NewEnviron{tikzbottomfigure}

\begin{document}

  \begin{center}                    % {figure}[h!]
  \centering                        % %(for figure)
  \includegraphics[width=1.0\textwidth]{/tmp/test.png}
  \captionof{figure}[shortdesc]{    % \caption[shortdesc]{
  caption lorem ipsum dolor sit amet, text line 01
  caption consectetur adipisicing elit text line 02
  caption text line 03
  }
  \label{fig:test1}
  \end{center}                      % {figure}

  % (c4)

  text here ... \par
  ... to test figure scale on bottom\par
  ... to test figure bottom scaling\par
  ... to test figure scale - is ok.\par

  % \runsplitfp{%
  \begin{tikzbottomfigure}
  \centering % algo passes with or without this (prefix before \includegraphics)
  \includegraphics[width=1.0\textwidth]{/tmp/test.png}
  \captionof{figure}[shortdesc]{    % \caption[shortdesc]{
  caption lorem ipsum dolor sit amet, text line 01
  caption consectetur adipisicing elit text line 02
  caption text line 03
  }
  \label{fig:test2}
  \end{tikzbottomfigure}
  % } % \runsplitfp

% (c5)
\end{document}


% (c0)
% http://tex.stackexchange.com/questions/4736/what-is-the-difference-between-fragile-and-robust-commands
% using e-TeX's \protected system to prevent crashing at typeouts here!
% (just \string{#1} doesn't work)
% http://tex.stackexchange.com/questions/49056/optional-arguments-in-def
% http://tex.stackexchange.com/questions/57229/on-unprotecting-expanding-protected-macros-or-the-space-after-command-name
% http://tex.stackexchange.com/questions/14390/how-can-one-pass-the-contents-of-a-latex-environment-to-a-macro

\def\splitatcaptionof#1\captionof#2\relax{ %
  \protected\def\splcofA{#1} %
  \protected\def\splcofB{#2} %
  \typeout{A: \splcofA^^JB: \splcofB} % A: \splcofA  B: \splcofB
}
\def\testsplcof#1{\splitatcaptionof#1\relax}

% nope; croaks on [],{}
\def\splitfigurepatternOld\includegraphics\[#1\]\{#2\}\captionof#3\label#4{%
  \protected\def\sfpA{#1} %
  \protected\def\sfpB{#2} %
  \protected\def\sfpC{#3} %
  \protected\def\sfpD{#4} %
  \typeout{A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC^^J D:
\meaning\sfpD^^J }
}

% (c1)
% if the split character doesn't occur in input - runaway argument!
% if it does, the final #3 will contain a single character,
% unless we put in a "break" token; here just chose arbitrarily
% a previously undefined token `\e` ...
% this splits: ...[width=1.0\textwidth ]{/tmp/test.png}
\def\splitoneoptstr#1[#2]#3\e{%
  \def\soosA{#1} %
  \def\soosB{#2} %
  \def\soosC{#3} %
  \typeout{srp A: \meaning\soosA^^J B: \meaning\soosB^^J C: \meaning\soosC} %
}
% ... then, the call also must have the break token `\e` before the \relax:
\def\runsplitoos#1{\splitoneoptstr#1\e\relax}

% this one splits entire figure pattern, containing:
% \includegraphics...\captionof...\label...
% and uses \runsplitoos for the includegraphics opts
\def\splitfigurepattern\includegraphics#1\captionof#2\label#3{%
  \protected\def\sfpA{#1} %
  \protected\def\sfpB{#2} %
  \protected\def\sfpC{#3} %
  \typeout{sfp A: \meaning\sfpA^^J B: \meaning\sfpB^^J C: \meaning\sfpC } %
  % \expandafter\runsplitoos\sfpA % Runaway argument?
  \edef\tcp{\meaning\sfpA} \typeout{tcp \tcp} %
  % \expandafter\runsplitoos{\tcp} % Runaway argument?
  % \expandafter\runsplitoos\tcp % passes;
  \expandafter\expandafter\runsplitoos{\tcp} % passes;
}

% (c2)
\newenvironment{tikzbottomfigureNOPE}
{ % start \begin env.
% start calling \runsplitfp{%
\def\contents\begingroup % so we open a brace?
} % stop \begin env.
{ % start \end env.
\endgroup % \endgroup % close brace? cannot
} % stop end env.

% (c3)
% note, the \expandafter\edef must be outside of {node .. includegraphics},
% else spurious space is introduced!
%\traceon %
%\includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
%\includegraphics[height=\imgheight pt,\protect\sfpA,keepaspectratio]{\sfpB}%
% sfpA needs to be expanded here first? not really, it contains
% \textwidth; it just needs to be expanded before \includegraphics;
% same for "File `\sfpB ' not found."
%\edef\tmpB{\sfpB} % \tmpB ->\sfpB: ! LaTeX Error: File `\sfpB ' not found.
\expandafter\edef\expandafter\tmpB\expandafter{\sfpB} % better: File `{/tmp/test.png} ' not found.
% now one more edef to get rid of the braces:
% \edef\tmpBB\tmpB - undef; \edef\tmpBB{\tmpB} - same as before; has braces
\expandafter\edef\expandafter\tmpBB\tmpB \typeout{BB \tmpBB}% ok: BB /tmp/test.png
% finally the includegraphics - have to expand \sfpA
% inline here (as it may contain \textwidth etc):
\expandafter\includegraphics\expandafter[\sfpA,height=\imgheight pt,
keepaspectratio,]{\tmpBB}%

% (c4)
%   % http://tex.stackexchange.com/questions/14512/how-to-define-a-figure-size-so-that-it-consumes-the-rest-of-a-page/14514#14514
%   % needs texing twice:
%   \begin{tikzpicture}[overlay,remember picture]
%     % Caption
%     \node [anchor=south west,outer sep=0pt,inner sep=0pt,text width=\textwidth] (caption) at (current page text area.south west) {%
%       \captionof{figure}[shortdesc]{ %
%       caption lorem ipsum dolor sit amet, text line 01
%       caption consectetur adipisicing elit text line 02
%       caption text line 03
%       }%
%       \label{fig:test2} % has to stand after the caption, to get its number
%     };
%     % Image
%     \path let \p0 = (0,0), \p1 = (caption.north) in
%       node [inner sep=0pt,outer sep=0pt,anchor=south] at (\x1,\y1) {%
%         \pgfmathsetmacro\imgheight{\y0-\y1-\abovecaptionskip}%
%         \includegraphics[height=\imgheight pt,width=\textwidth,keepaspectratio]{/tmp/test.png}%
%     };
%   \end{tikzpicture}%

% (c5)
% \edef\tcp{\meaning\sfpA} \typeout{tcp \tcp}
% \typeout{A: \meaning\splcofA^^JB: \meaning\splcofB}
% A: \protected macro:->\includegraphics [width=1.0\textwidth ]{/tmp/test.png}
% B: \protected macro:->{figure}[shortdesc]{ caption lorem ipsum dolor sit amet,
% text line 01 caption consectetur adipisicing elit text line 02 caption text lin
% e 03 } \label {fig:test1}

相关内容