将代码从末尾附加到环境的开头

将代码从末尾附加到环境的开头

我怎样才能将环境末尾生成的内容放入环境开头?我认为这要么非常简单,要么相当棘手,但我不知道该怎么做。

示例渲染

梅威瑟:

\documentclass{article}

\usepackage{etoolbox}

\makeatletter

%% floruit handlers:

\newcommand\fl@years{}

\newcommand\fl@handler[1]{
    \ifnumcomp{#1}{<}{\fl@from}{\renewcommand\fl@from{#1}}{}
    \ifnumcomp{#1}{>}{\fl@to}{\renewcommand\fl@to{#1}}{}
}

\newcommand\fl@output{
    \newcommand\fl@from{10000}
    \newcommand\fl@to{0}
    \forlistloop{\fl@handler}{\fl@years}
    \textit{\ifnumcomp{\fl@from}{=}{\fl@to}{fl.~\fl@to}{fl.~\fl@from--\fl@to}}
}

\newbool{fl_called}

\newcommand\floruit[1]{#1\booltrue{fl_called}\listadd\fl@years{#1}}

%% person environment:

\newcounter{person}

\newenvironment{person}[1]{
    \refstepcounter{person}
    \renewcommand\fl@years{}
    \textbf{\theperson:~#1}\par
}{
    \ifbool{fl_called}{\par\fl@output}{}\par
}

\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\begin{person}{Old MacDonald}
Old MacDonald had a farm in \floruit{1923}, but appears to have sold it by \floruit{1940}.
\end{person}

\begin{person}{Gary Cooper}
Gary Cooper starred in High Noon (\floruit{1952})...
\end{person}

\begin{person}{John Doe}
Blah blah (\floruit{1912}), more blah (\floruit{1930}) \& finally blah (\floruit{1931}).
\end{person}

\begin{person}{Jane Doe}
No floruit here...
\end{person}

The floruit should be with the name like so:

\textbf{3: John Doe} \textit{fl. 1912--1931}\par
Blah blah (1912), more blah (1930) \& finally blah (1931).\par

\end{document}

答案1

这是第一个启动器(稍后会随着时间推移不断改进)

\fl@from这个想法是使用 - 设施将和的数据\fl@to作为“标签”信息写入.aux文件(在下次编译运行时再次读取),zref然后使用 再次提取存储的信息\zref@extract

在演讲中zref fromto是属性。

\documentclass{article}

\usepackage{etoolbox}
\usepackage{zref}


\makeatletter

%% floruit handlers:

\newcommand\fl@from{10000}
\newcommand\fl@to{0}
\newcommand\fl@years{}

\newcommand\fl@handler[1]{
    \ifnumcomp{#1}{<}{\fl@from}{\renewcommand\fl@from{#1}}{}
    \ifnumcomp{#1}{>}{\fl@to}{\renewcommand\fl@to{#1}}{}
}


\newcommand{\fl@output}[1]{%
    \renewcommand\fl@from{10000}
    \renewcommand\fl@to{0}
    \forlistloop{\fl@handler}{\fl@years}
    \zref@ifrefundefined{#1}{}{%
      \ifnum\zref@extract{#1}{from}=\fl@from
      \else
      \ifnum\zref@extract{#1}{from}=\zref@extract{#1}{to}
      \textit{\zref@extract{#1}{to}}%
      \else
      \textit{fl.~\zref@extract{#1}{from}--\zref@extract{#1}{to}}%
      \fi
      \fi
    }
}


\newbool{fl_called}

\newcommand\floruit[1]{#1\booltrue{fl_called}\listadd\fl@years{#1}}
\zref@newprop{from}[-1]{\fl@from}
\zref@newprop{to}[-1]{\fl@to}

\newcommand{\florlabel}[1]{%
\zref@labelbyprops{#1}{from,to}%
}



%% person environment:

\newcounter{person}

\newenvironment{person}[1]{
  \refstepcounter{person}%
  \edef\@oldcurrentlabel{\@currentlabel}
  \renewcommand\fl@years{}
  \textbf{\theperson:~#1} \fl@output{flordata:\number\value{person}}\par
}{%
  \ifbool{fl_called}{\par\fl@output{flordata:\number\value{person}}}{}\par
  %Restore the label data in case we have some \refstepcounter after \refstepcounter{person}
  \edef\@currentlabel{\@oldcurrentlabel}
  \florlabel{flordata:\number\value{person}}%
}

\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\begin{person}{Old MacDonald}
Old MacDonald had a farm in \floruit{1923}, but appears to have sold it by \floruit{1940}.
\end{person}

\begin{person}{Gary Cooper}
Gary Cooper starred in High Noon (\floruit{1952})...
\end{person}

\begin{person}{John Doe}
Blah blah (\floruit{1912}), more blah (\floruit{1930}) \& finally blah (\floruit{1931}).
\end{person}

\begin{person}{Jane Doe}
No floruit here...
\end{person}

The floruit should be with the name like so:

\textbf{3: John Doe} \textit{fl. 1912--1931}\par
Blah blah (1912), more blah (1930) \& finally blah (1931).\par

\end{document}

我会尝试改进列表处理。etoolbox在我看来,布尔值很棘手。

在此处输入图片描述

**一些更新的expl3功能是为了获得“更清洁”的代码

\documentclass{article}
\usepackage{xparse}
\usepackage{zref}

\makeatletter

\ExplSyntaxOn

\cs_generate_variant:Nn \prop_put:Nnn {Nxx}
\cs_generate_variant:Nn \int_set:Nn {Nx}


% Storage containers
\seq_new:N \l_meide_flordata_seq
\prop_new:N \l_meide_flordata_prop

% Clear the list
\NewDocumentCommand{\ClearFlordata}{}{%
  \seq_clear:N \l_meide_flordata_seq
}

\NewDocumentCommand{\floruit}{m}{%
  \seq_put_right:Nn \l_meide_flordata_seq {#1}
  \DisplayInlineFlorData{#1}%
}

\DeclareExpandableDocumentCommand{\ExtractListProp}{m}{%
  \prop_item:Nn \l_meide_flordata_prop {#1}%
}


\int_new:N \l_meide_from_int
\int_new:N \l_meide_to_int
\NewDocumentCommand{\ProcessFlorData}{}{%
  % Checking first whether there's something in the list at all
  \seq_if_empty:NTF \l_meide_flordata_seq {%
    \prop_put:Nnx \l_meide_flordata_prop {from} { 0 } 
    \prop_put:Nnx \l_meide_flordata_prop {to} { 0 } 
  }{%
    \prop_put:Nnx\l_meide_flordata_prop {from} { \seq_item:Nn \l_meide_flordata_seq {1} } 
    \prop_put:Nnx\l_meide_flordata_prop {to} { \seq_item:Nn \l_meide_flordata_seq {2} } 
    \int_compare:nNnTF {\seq_count:N \l_meide_flordata_seq } > {1} {%
      \prop_put:Nnx \l_meide_flordata_prop {to} {\seq_item:Nn \l_meide_flordata_seq {2}}
    }{
      \prop_put:Nnx \l_meide_flordata_prop {to} {\seq_item:Nn \l_meide_flordata_seq {1}}
    }
  }
  % Determine the min and max of the list and store it to the from or to properties
  \seq_map_inline:Nn \l_meide_flordata_seq {
    \int_set:Nx \l_tmpa_int {\prop_item:Nn \l_meide_flordata_prop {from} }
    \int_set:Nx \l_tmpb_int {\int_min:nn {##1} {\l_tmpa_int }}
    \prop_put:NnV \l_meide_flordata_prop { from } { \l_tmpb_int }
    \int_set:Nx \l_tmpa_int {\prop_item:Nn \l_meide_flordata_prop {to} }
    \int_set:Nx \l_tmpb_int {\int_max:nn {##1} {\l_tmpa_int }}
    \prop_put:NnV \l_meide_flordata_prop { to } { \l_tmpb_int }
  }
  \edef\@currentlabel{\@oldcurrentlabel}
  % Do not write a label if there's nothing to write, i.e. the sequence is empty!
  \seq_if_empty:NF \l_meide_flordata_seq {
    \florlabel{flordata:\number\value{person}}%
  }
}

\ExplSyntaxOff

% Defines the format for the numbers
\NewDocumentCommand{\FormatFlorData}{om}{%
  \IfValueTF{#1}{%
    \textit{fl.~#1 -- #2}%
  }{%
    \textit{#2}%
  }%
}


% A simple wrapper for the display of the inline data given with \floruit
\NewDocumentCommand{\DisplayInlineFlorData}{+m}{%
  (#1)%
}

% Display the numbers

\NewDocumentCommand{\DisplayFlorData}{m}{%
  % Check first if the reference is defined
  \zref@ifrefundefined{#1}{}{%
    \ifnum\zref@extract{#1}{from}=\zref@extract{#1}{to}
    \FormatFlorData{\zref@extract{#1}{from}}%
    \else
    \FormatFlorData[\zref@extract{#1}{from}]{\zref@extract{#1}{to}}%%
    \fi
  }
}

% zref - related code

% Define zref - properties and fill them with the `\prop` - key - value of the same name
% This could be done in a loop using expl3 - loops etc.

\zref@newprop{from}[-1]{\ExtractListProp{from}}
\zref@newprop{to}[-1]{\ExtractListProp{to}}

\newcommand{\florlabel}[1]{%
  \zref@labelbyprops{#1}{from,to}%
}

% Basic Environment and counter definition


\newcounter{person}

\NewDocumentEnvironment{person}{+m}{%
  \ClearFlordata%
  \refstepcounter{person}
  % Store the last label for future purposes
  \edef\@oldcurrentlabel{\@currentlabel}
  \textbf{\theperson:~#1} \DisplayFlorData{flordata:\number\value{person}}\par
}{%
  % Now evaluate the data given in the environment and write the label accordingly. 
  \ProcessFlorData%
}

\makeatother

\begin{document}
\begin{person}{Old MacDonald}
Old MacDonald had a farm in \floruit{1923}, but appears to have sold it by \floruit{1940}.
\end{person}
\begin{person}{Gary Cooper}
Gary Cooper starred in High Noon \floruit{1952}...
\end{person}

\begin{person}{John Doe}
Blah blah \floruit{1912}, more blah \floruit{1930} \& finally blah \floruit{1931}.
\end{person}

\begin{person}{Mr. Gumby}
Was active in \floruit{1900}, \floruit{1855}, \floruit{2017}, \floruit{1066}.
\end{person}


\begin{person}{Jane Doe}
No floruit here...
\end{person}

\end{document}

答案2

你可以对环境主体进行person两次处理(得益于environ)。第一次处理提取年份,第二次处理设置内容设置\fl@output

第一次处理发生在我们存储\BODY在临时框中时。这意味着没有设置任何内容,但所有内容都“贯穿始终”。为此,我们必须使列表添加和“来自”/“到”存储g全局化。

在此处输入图片描述

\documentclass{article}

\usepackage{etoolbox,environ}

\makeatletter

%% floruit handlers:

\newcommand\fl@years{}

\newcommand\fl@handler[1]{%
  \ifnumcomp{#1}{<}{\fl@from}{\gdef\fl@from{#1}}{}%
  \ifnumcomp{#1}{>}{\fl@to}{\gdef\fl@to{#1}}{}%
}

\newcommand\fl@output{%
  \gdef\fl@from{10000}%
  \gdef\fl@to{0}%
  \forlistloop{\fl@handler}{\fl@years}%
  \textit{\ifnumcomp{\fl@from}{=}{\fl@to}{fl.~\fl@to}{fl.~\fl@from--\fl@to}}%
}

\newbool{fl_called}

\newcommand\floruit[1]{#1\global\booltrue{fl_called}\listgadd\fl@years{#1}}

%% person environment:

\newcounter{person}

\NewEnviron{person}[1]{%
  \renewcommand\fl@years{}%
  \boolfalse{fl_called}%
  \sbox\@tempboxa{\BODY}% Process body once to capture \floruit's
  \refstepcounter{person}%
  \textbf{\theperson:~#1}\ifbool{fl_called}{~\fl@output}{}\par
  \BODY
  \par
}

\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\begin{person}{Old MacDonald}
Old MacDonald had a farm in \floruit{1923}, but appears to have sold it by \floruit{1940}.
\end{person}

\begin{person}{Gary Cooper}
Gary Cooper starred in High Noon (\floruit{1952})...
\end{person}

\begin{person}{John Doe}
Blah blah (\floruit{1912}), more blah (\floruit{1930}) \& finally blah (\floruit{1931}).
\end{person}

\begin{person}{Jane Doe}
No floruit here...
\end{person}

The floruit should be with the name like so:

\textbf{3: John Doe} \textit{fl. 1912--1931}\par
Blah blah (1912), more blah (1930) \& finally blah (1931).\par

\end{document}

相关内容