根据类型区分引用(参数扩展问题)

根据类型区分引用(参数扩展问题)

由于我使用未编号的节,因此我希望有一种变体,\autoref在分段时使用名称而不是数字,但在其他环境中保持其通常的行为。我想出了这段简单的代码,但我无法让它工作。

\documentclass{article}
\usepackage{xstring, hyperref, nameref}
\setcounter{secnumdepth}{-1}
\makeatletter
\newcommand{\KSautoref}[1]{
    \edef\KS@RefType{\expandafter\@fourthoffive\csname r@#1\endcsname}
    \newif\ifKSSectioning\KSSectioningfalse
    \IfBeginWith{\KS@RefType}{chapter}{\KSSectioningtrue}{}
    \IfBeginWith{\KS@RefType}{section}{\KSSectioningtrue}{}
    \IfBeginWith{\KS@RefType}{subsection}{\KSSectioningtrue}{}
    \IfBeginWith{\KS@RefType}{subsubsection}{\KSSectioningtrue}{}
    \IfBeginWith{\KS@RefType}{paragraph}{\KSSectioningtrue}{}
    \IfBeginWith{\KS@RefType}{subparagraph}{\KSSectioningtrue}{}
    \ifKSSectioning\chaptername\nameref{#1}\else\autoref{#1}\fi
}
\makeatother
\begin{document}
\section{Test} \label{test}
See \KSautoref{test}.
\end{document}

当我尝试编译它时,出现以下错误:

! Argument of \@fourthoffive has an extra }.
<inserted text>
                \par
l.19 See \KSautoref{test}
                         .
?

使用\tracingall我得到这些额外的信息:

{\edef}
{\expandafter}
{\csname}

\@fourthoffive #1#2#3#4#5->#4
#1<-\r@test

我怎样才能\r@test进行扩展,以便它不只是用作第一个参数?

如果有一个包提供该功能,我宁愿使用它,但我仍然想了解有关扩展的一些信息......

答案1

你只做了一次扩展,但你需要两次。

\expandafter\@fourthoffive\csname r@#1\endcsname

就像#1=test例子中的那样,你会得到

\expandafter\@fourthoffive\csname r@test\endcsname

变成

\@fourthoffive\r@test

所以你需要\expandafter\expandafter\expandafter

这是一个更好的版本:

\documentclass{book}
\usepackage{xstring, hyperref, nameref}
\setcounter{secnumdepth}{-1}
\makeatletter
\newif\ifKSSectioning
\newcommand{\KSautoref}[1]{%
  \KSSectioningfalse
  \expandafter\ifx\csname r@#1\endcsname\relax
    \ref{#1}%
  \else
    \protected@edef\KS@RefType{\expandafter\expandafter\expandafter\@fourthoffive\csname r@#1\endcsname}%
    \IfBeginWith{\KS@RefType}{chapter}{\KSSectioningtrue}{}%
    \IfBeginWith{\KS@RefType}{section}{\KSSectioningtrue}{}%
    \IfBeginWith{\KS@RefType}{subsection}{\KSSectioningtrue}{}%
    \IfBeginWith{\KS@RefType}{subsubsection}{\KSSectioningtrue}{}%
    \IfBeginWith{\KS@RefType}{paragraph}{\KSSectioningtrue}{}%
    \IfBeginWith{\KS@RefType}{subparagraph}{\KSSectioningtrue}{}%
    \ifKSSectioning\chaptername~\nameref{#1}\else\autoref{#1}\fi
  \fi
}
\makeatother
\begin{document}
\section{Test} \label{test}
See \KSautoref{test}.
\end{document}

添加的条件是为了应对引用尚未设置的情况;我将其移到\newif定义之外,因为不断创建新条件是没有用的,只需在宏开始时将其设置为 false 即可。

我还使用过\protected@edef标题包含\emph无法生存的宏的情况\edef


expl3以下是使用正则表达式的实现。

\documentclass{book}
\usepackage{xparse,l3regex, hyperref, nameref}
\setcounter{secnumdepth}{-1}

\ExplSyntaxOn
% Document level commands
\NewDocumentCommand \KSautoref { m }
 {
  \pazathoth_ks_autoref:n { #1 }
 }

% variables
\tl_new:N \l__pazathoth_type_tl
\regex_const:Nn \c_pazathoth_class_regex
 {
  \A (chapter|section|subsection|subsubsection|paragraph|subparagraph) .*
 }

% internal functions
\cs_new_protected:Npn \pazathoth_ks_autoref:n #1
 {
  \cs_if_eq:cNTF { r@#1 } \scan_stop:
   { % if the reference is undefined go to the standard method
    \ref { #1 }
   }
   { % else scan for a named reference
    \__pazathoth_ks_autoref:cn { r@#1 } { #1 }
   }
 }

\cs_new_protected:Npn \__pazathoth_ks_autoref:Nn #1 #2
 {
  % get the fourth item in `r@#1`
  \tl_set:Nx \l__pazathoth_type_tl { \tl_item:Vn #1 { 4 } }
  % check if the fourth item starts with a name
  \regex_replace_all:NnNTF \c_pazathoth_class_regex { \1 } \l__pazathoth_type_tl
   { % the replacement was successful; use the section name
    \use:c { \l__pazathoth_type_tl name } \nobreakspace \nameref { #2 }
   }
   { % no name, use \autoref
    \autoref { #2 }
   }
 }

% function variants
\cs_generate_variant:Nn \cs_if_eq:NNTF { c }
\cs_generate_variant:Nn \tl_item:nn { V }
\cs_generate_variant:Nn \__pazathoth_ks_autoref:Nn { c }

\ExplSyntaxOff

\providecommand{\sectionname}{Section}

\begin{document}
\section{Test \emph{x}} \label{test}
See \KSautoref{test}.

\begin{enumerate}
\item\label{item} x
\end{enumerate}

See \KSautoref{item}.

\end{document}

在此处输入图片描述

相关内容