itemize 中由宏组成的项目的字母顺序排序

itemize 中由宏组成的项目的字母顺序排序

这是该主题的延续: 按字母顺序显示 itemize 中的项目

但遗憾的是我没有足够的声誉来在那里发表评论。

@Werner 提出的方法非常完美,即使您需要在列表中显示格式化的文本。但我还有一个问题:我需要对包含格式的项目进行排序,并且需要能够编辑这些项目的文本和格式。因此我使用宏,所以我不能将这个技巧与包含纯文本的可选项一起使用。

以下是 MWE:

\documentclass{article}
\usepackage{datatool}% http://ctan.org/pkg/datatool
\newcommand{\sortitem}[1]{%
  \DTLnewrow{list}% Create a new entry
  \DTLnewdbentry{list}{description}{#1}% Add entry as description
}
\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}% Create new/discard old list
}{%
  \DTLsort{description}{list}% Sort list
  \begin{itemize}%
    \DTLforeach*{list}{\theDesc=description}{%
      \item \theDesc}% Print each item
  \end{itemize}%
}
\begin{document}

% I need to be able to edit these items and their formatting without changing the rest of my code
\newcommand{\firstitem}{ISDYNSTP:  Is dynamic time step used ?}
\newcommand{\seconditem}{\textit{ISCDCA:}}
\newcommand{\thirditem}{\textbf{MVAR}}
\newcommand{\fourthitem}{IS2TL}

Default:
\begin{itemize}
  \item \firstitem
  \item \seconditem
  \item \thirditem
  \item \fourthitem
\end{itemize}

Sorted:
\begin{sortedlist}
  \expandafter\sortitem\expandafter{\firstitem}
  \expandafter\sortitem\expandafter{\seconditem}
  \expandafter\sortitem\expandafter{\thirditem}
  \expandafter\sortitem\expandafter{\fourthitem}
\end{sortedlist}

\end{document}

我添加了,\expandafter因此宏被扩展,所以项目被很好地排序,除非它们具有类似的某些格式\textbf,否则它们只会首先显示而不按任何字母顺序排列。

任何想法 ?

答案1

我建议添加结构;命令\newitem(补充\useitem)将把实际数据与格式指令分开。

\documentclass{article}

\usepackage{datatool}

\makeatletter
\newcommand{\sortitem}{\@ifnextchar\bgroup\@sortitem{\expandafter\@sortitem}}

\newcommand{\@sortitem}[2]{%
  \DTLnewrow{list}% Create a new entry
  \DTLnewdbentry{list}{description}{#1}% Add entry as description
  \DTLnewdbentry{list}{formatting}{#2}% Add formatting info
}
\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}% Create new/discard old list
}{%
  \DTLsort{description}{list}% Sort list
  \begin{itemize}%
    \DTLforeach*{list}{\theDesc=description,\theForm=formatting}{%
      \item \theForm{\theDesc}}% Print each item
  \end{itemize}%
}
\newcommand{\newitem}[3]{\newcommand#1{{#2}{#3}}}
\newcommand{\useitem}[1]{\expandafter\@useitem#1}
\newcommand{\@useitem}[2]{#2{#1}}
\makeatother

\begin{document}

% I need to be able to edit these items and their formatting without changing the rest of my code
\newitem{\firstitem}{ISDYNSTP:  Is dynamic time step used ?}{}
\newitem{\seconditem}{ISCDCA:}{\textit}
\newitem{\thirditem}{MVAR}{\textbf}
\newitem{\fourthitem}{IS2TL}{}

\useitem\seconditem % just for example

Sorted:
\begin{sortedlist}
  \sortitem\firstitem
  \sortitem\seconditem
  \sortitem\thirditem
  \sortitem\fourthitem
  \sortitem{AAAAfirst}{\textsc}
\end{sortedlist}

\end{document}

在此处输入图片描述

答案2

改编@Werner 的第二部分回答对于您链接的问题以及可选的纯文本排序,以下内容可能适合您的需要。

对于每个格式化命令,您必须定义一个具有相同名称但带有后缀的单独命令,plain该后缀定义用于排序的纯文本。该\sortitem命令已被修改,因此如果传递了一个参数,则首先测试它是否是命令(由此改编形式提供回答由 egreg 提供)。如果存在,则plain测试变体,如果存在,则将其用作排序标签。如果不存在,则使用传递的参数。

您的 MWE(附带一些额外的测试条目):

\documentclass{article}
\usepackage{datatool}% http://ctan.org/pkg/datatool

%from egreg at: https://tex.stackexchange.com/a/42337/89497
\makeatletter
\begingroup\lccode`\|=`\\
\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}}
\newcommand{\macroname}[1]{\expandafter\removebs\string#1}

%adapted from https://tex.stackexchange.com/a/42337/89497
\newif\ifisamacro
\begingroup\lccode`\|=`\\
\lowercase{\endgroup\def\nameifmacro#1#2\nil{\if#1|#2\else\relax\fi}}
\makeatother

\newcommand{\sortitem}[2][\relax]{%
    \DTLnewrow{list}% Create a new entry
    \ifx#1\relax%no option passed...see if #2 is a macro and has a plain-text variant
        \edef\testifmacro{\expandafter\nameifmacro\string#2\nil}%test if it is a macro. will be the name if it is a macro, \relax if not
        \expandafter\ifx\testifmacro\relax%then it is not a macro...
            \DTLnewdbentry{list}{sortlabel}{#2}%
        \else%it is a macro
            \expandafter\ifcsname\macroname{#2}plain\endcsname%then it has a plain text option defined              
                \edef\rslt{\noexpand\DTLnewdbentry{list}{sortlabel}{\expandafter\expandafter\expandafter\expandonce\expandafter\csname\macroname{#2}plain\endcsname}}%
            \else%no plain text option...expand macro once to pass contents for sorting
                \edef\rslt{\noexpand\DTLnewdbentry{list}{sortlabel}{\expandonce#2}}%
            \fi
            \rslt%execute the \DTLnewdbentry command
        \fi
  \else
    \DTLnewdbentry{list}{sortlabel}{#1}% Add entry sortlabel (optional argument)
  \fi%
  \DTLnewdbentry{list}{description}{#2}% Add entry description
}
\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}% Create new/discard old list
}{%
  \DTLsort{sortlabel}{list}% Sort list
  \begin{itemize}%
    \DTLforeach*{list}{\theDesc=description}{%
      \item \theDesc}% Print each item
  \end{itemize}%
}
\begin{document}

% I need to be able to edit these items and their formatting without changing the rest of my code
\newcommand{\firstitem}{ISDYNSTP:  Is dynamic time step used ?}
\newcommand{\seconditem}{\textit{ISCDCA:}}
\newcommand{\thirditem}{\textbf{MVAR}}
\newcommand{\fourthitem}{IS2TL}

%append plain to the end of the associated macroname to define the plain text variant for it.
\newcommand{\seconditemplain}{ISCDCA:}
\newcommand{\thirditemplain}{MVAR}

Default:
\begin{itemize}
  \item \firstitem
  \item \seconditem
  \item \thirditem
  \item \fourthitem
\end{itemize}

Sorted:
\begin{sortedlist}
    \sortitem{b}
    \sortitem{\firstitem}
    \sortitem{\seconditem}
    \sortitem{seconditem}
    \sortitem{\thirditem}
    \sortitem{\fourthitem}
    \sortitem{A}
\end{sortedlist}
\end{document}

产量:

排序结果

包括初始测试,\sortitem{seconditem}以便不是根据 的内容进行排序\seconditemplain。我已尝试将参数和引用命令的扩展限制在其内容中,以sortlabel防止其中断。因此,如果没有plain提供变体,则它们将根据\内容开头的 进行排序(据我所知)并将出现在列表的开头。如果命令plain实际上不是纯文本,这也可以防止它中断。请注意,如果在左括号和命令之间有空格(例如\sorteditem{ \seconditem}),它将中断。

一个不错的补充是将格式化和纯文本命令的创建包装到单个调用中,例如:

\newcommand{\newsorteditem}[3][\relax]{%
    \ifx#1\relax\else
        \expandafter\newcommand\expandafter{\csname#3plain\endcsname}{#1}%
    \fi
    \expandafter\newcommand\expandafter{\csname#3\endcsname}{#2}}%

其名称将类似于\newsorteditem[plain text]{formatted text}{commandname}

答案3

我找到了一种使用@Werner 方法的方法,而不必自己编写我试图排序的宏的纯文本版本。

它使用包\pdfstringdefhyperref提取宏的纯文本形式。

使用此方法时要小心,因为它对任何格式都不安全,例如,我必须为 定义一个例外\textcolor。它对空格也表现得很奇怪,但对我来说这不是问题。

以下是代码:

\documentclass{article}

\usepackage{datatool}
\usepackage{xcolor}
\usepackage{hyperref}

\newcommand{\sortitem}[2][\relax]{%
  \DTLnewrow{list}% Create a new entry
  \ifx#1\relax
    \DTLnewdbentry{list}{sortlabel}{#2}% Add entry sortlabel (no optional argument)
  \else
    \DTLnewdbentry{list}{sortlabel}{#1}% Add entry sortlabel (optional argument)
  \fi%
  \DTLnewdbentry{list}{description}{#2}% Add entry description
}
\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}% Create new/discard old list
}{%
  \DTLsort{sortlabel}{list}% Sort list
  \begin{itemize}%
    \DTLforeach*{list}{\theDesc=description}{%
      \item \theDesc}% Print each item
  \end{itemize}%
}

\pdfstringdefDisableCommands{\def\textcolor#1{}}

\begin{document}

\newcommand{\first}{ISDYNSTP: Is dynamic time step used ?}
\newcommand{\second}{\textcolor{blue}{ISCDCA:}}
\newcommand{\third}{\textbf{MVAR}}
\newcommand{\fourth}{IS2TL}

List of items :
\begin{itemize}
\item \first
\item \second
\item \third
\item \fourth
\end{itemize}
\bigskip

\pdfstringdef\firstplain{\first}
\pdfstringdef\secondplain{\second}
\pdfstringdef\thirdplain{\third}
\pdfstringdef\fourthplain{\fourth}

List of "plain" items :
\begin{itemize}
\item \firstplain
\item \secondplain
\item \thirdplain
\item \fourthplain
\end{itemize}
\bigskip

Sorted items (without expandafter) :
\begin{sortedlist}
  \sortitem[\firstplain]{\first}
  \sortitem[\secondplain]{\second}
  \sortitem[\thirdplain]{\third}
  \sortitem[\fourthplain]{\fourth}
\end{sortedlist}
\bigskip

Sorted items (with expandafter) :
\begin{sortedlist}
  \expandafter\sortitem\expandafter[\firstplain]{\first}
  \expandafter\sortitem\expandafter[\secondplain]{\second}
  \expandafter\sortitem\expandafter[\thirdplain]{\third}
  \expandafter\sortitem\expandafter[\fourthplain]{\fourth}
\end{sortedlist}
\bigskip

\end{document}

正如您所看到的,如果您尝试该代码示例,您需要使用它\expandafter来获得正确的结果。

下面是一个更复杂的例子,它可以处理要排序的宏列表。

\documentclass{article}

\usepackage{datatool}
\usepackage{xcolor}
\usepackage{etoolbox}
\usepackage{xparse}

\usepackage{hyperref}

\makeatletter

\newcommand{\sortitem}[2][\relax]{%
  \DTLnewrow{list}% Create a new entry
  \ifx#1\relax
    \DTLnewdbentry{list}{sortlabel}{#2}% Add entry sortlabel (no optional argument)
  \else
    \DTLnewdbentry{list}{sortlabel}{#1}% Add entry sortlabel (optional argument)
  \fi%
  \DTLnewdbentry{list}{description}{#2}% Add entry description
}
\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}% Create new/discard old list
}{%
  \DTLsort{sortlabel}{list}% Sort list
  \begin{itemize}%
    \DTLforeach*{list}{\theDesc=description}{%
      \item \theDesc}% Print each item
  \end{itemize}%
}

\pdfstringdefDisableCommands{\def\textcolor#1{}}

%%%  Lists handling %%%

\newcommand{\addlocallist}{\listadd\locallists@dummy}
\NewDocumentCommand{\parsespacelist}{ >{\SplitList{ }} m } {%
    \ProcessList{#1}{\addlocallist}%
}
\NewDocumentCommand{\parsecommalist}{ >{\SplitList{,}} m } {%
    \ProcessList{#1}{\addlocallist}%
}
\newcommand{\parselist}[3][,]{%
    \renewcommand\addlocallist{\listadd#3}%
    \undef#3%
    \ifstrequal{#1}{ }{\parsespacelist{#2}}{\parsecommalist{#2}}%
}

\newcommand{\addtosortedlist}[1]{%
    \pdfstringdef\plaintexttemp{#1}%
    \expandafter\sortitem\expandafter[\plaintexttemp]{#1}
}%

\newcommand{\ruleslist}[1]{%
    \parselist[,]{#1}{\locallists@ruleslist}%
    \begin{sortedlist}%
        \forlistloop{\addtosortedlist}{\locallists@ruleslist}%
    \end{sortedlist}%
}

\begin{document}

\newcommand{\first}{ISDYNSTP: Is dynamic time step used ?}
\newcommand{\second}{\textcolor{blue}{ISCDCA:}}
\newcommand{\third}{\textbf{MVAR}}
\newcommand{\fourth}{IS2TL}

List of items :
\begin{itemize}
\item \first
\item \second
\item \third
\item \fourth
\end{itemize}
\bigskip

Ordered list :

\ruleslist{\first, \second, \third, \fourth}

\end{document}

相关内容