我怎样才能将环境末尾生成的内容放入环境开头?我认为这要么非常简单,要么相当棘手,但我不知道该怎么做。
梅威瑟:
\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
from
和to
是属性。
\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}