由于我使用未编号的节,因此我希望有一种变体,\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}