将 \ref{} 作为字符串操作

将 \ref{} 作为字符串操作

我想使用宏来xstring对由 a 生成的字符串进行操作\ref{}

具体来说,我有一个宏,它“填充”十进制数,以便按字典顺序排序;换句话说,12.9 应该变成 00012.00009。\padref{}下面的宏就是这么做的。

但问题是我想让它对 进行操作\ref{},但这不起作用:字符串以某种方式被区别对待。 \StrCut无法看到它包含一个点,但\StrLen能够看到它有多长。

我怀疑这与扩张有关,但我最初的尝试\edef没有成功。

如果它很重要,那么潜在的动机是我有一堆对列表项的引用(如下所示\ref{one}),我想将其用作\padref{}索引键。

\documentclass{amsart}

\usepackage{enumitem}
\usepackage{ifthen,calc}
\usepackage{xstring}
\parskip3ex
% takes a reference like 2.9 or 10.1 and pads it to five digits, so 00002.00009 and 00010.00001
% lexicographical sorting on this will ``do the right thing''
\newcommand\padref[1]{%
  \StrCut{#1}{.}\chap\ques%
  \StrLen{\chap}[\chaplen]%
  \StrLen{\ques}[\queslen]%
  \StrGobbleRight{00000}{\chaplen}%
  \chap%
  .%
  \StrGobbleRight{00000}{\queslen}%
  \ques%
}


\begin{document}


% this works, gives 00012.00009
Pad 12.9: \padref{12.9}


% this gives 001.1.00000
% the string is somehow not recognized (it "doesn't" contain a dot)
% but is also recognized (note that three characters were dropped from the first 00000)
Pad 1.1 given as a reference: \padref{\ref{one}}

% the following confuses me
\ref{one}
1.1
\ifthenelse{\equal{\ref{one}}{1.1}}{are the same}{are different}


This is just a silly list so I can have a reference.
\begin{enumerate}[label=\arabic*,ref=\arabic*.]
\item
  \begin{enumerate}[label=\arabic*,ref=\theenumi\arabic*]
  \item hi\label{one}
  \item there
  \end{enumerate}
\end{enumerate}

\end{document}

答案1

我们可以使用\getrefnumberfromrefcount并且避免enumitem添加括号的习惯。

\documentclass{amsart}
\usepackage{enumitem}
\usepackage{refcount}
\usepackage{xparse}

\ExplSyntaxOn

% user interface
\NewDocumentCommand{\padref}{m}
 {
  \newman_padref_main:n { #1 }
 }

% variables and constants
\int_const:Nn \c_newman_padref_padding_int { 5 } % change here
\tl_new:N \l__newman_padref_ref_tl
\seq_new:N \l__newman_padref_parts_seq
\seq_new:N \l__newman_padref_parts_out_seq

% utilities
\cs_set_eq:NN \newman_padref_getrefnumber:n \getrefnumber

% internal code
\cs_new_protected:Nn \newman_padref_main:n 
 {
  % save the expanded reference
  \tl_set:Nx \l__newman_padref_ref_tl
   {
    \newman_padref_getrefnumber:n { #1 }
   }
  % with enumitem we get unwanted braces; remove them recursively
  \__newman_padref_removebraces:N \l__newman_padref_ref_tl
  % split at periods
  \seq_set_split:NnV \l__newman_padref_parts_seq { . } \l__newman_padref_ref_tl
  % pad each part and output it with a period in between
  \seq_set_map:NNn
   \l__newman_padref_parts_out_seq
   \l__newman_padref_parts_seq
   { \__newman_padref_pad:n { ##1 } }
  \seq_use:Nn \l__newman_padref_parts_out_seq { . }
 }

\cs_new:Nn \__newman_padref_pad:n
 {% count the number of characters and pad up to the desired number
  \prg_replicate:nn { \c_newman_padref_padding_int - \tl_count:n { #1 } } { 0 } #1
 }

\cs_new:Nn \__newman_padref_removebraces:N
 {
  \int_compare:nT
   {
    \tl_count:N #1 < \tl_count_tokens:V #1 % there are braces
   }
   {
    \tl_set:Nx #1 { \tl_map_function:NN #1 \use:n } % remove braces
    \__newman_padref_removebraces:N #1              % restart the recursion
   }
 }
\cs_generate_variant:Nn \tl_count_tokens:n { V }

\ExplSyntaxOff

\begin{document}


Pad \ref{one} given as a reference: \padref{one}


This is just a silly list so I can have a reference.
\begin{enumerate}[label=\arabic*,ref=\arabic*.]
\item
  \begin{enumerate}[label=\arabic*,ref=\theenumi\arabic*]
  \item hi\label{one}
  \item there
  \end{enumerate}
\end{enumerate}

\end{document}

在此处输入图片描述

相关内容