8

I'm looking for a solution to my previous question "Relative chapter references", and find myself struggling with trying to get the target "type" of a label from the label itself.

Allow me to clarify: I want to determine whether a given label points to either a chapter, section, subsection, figure, table, etc.

Ideas? (cuz I'm plain out)

PS: the solution should be compatible with the hyperref package at the very least.

mpr
  • 3,646
  • Have you looked at the cleveref package? – cmhughes Nov 05 '11 at 21:07
  • @cmhughes: I can only imagine \lcnamecref could be of any use... but lack the skill to turn it into something usefull I'm afraid :S... could you provide an example? – mpr Nov 05 '11 at 21:28

1 Answers1

9
\documentclass{article}
\usepackage[ngerman]{babel}
\usepackage{hyperref}

\makeatletter

% Helper macro to extract the type (section,subsection...) or the type name
% out of the label reference. Works with hyperref only.
% Argument #1 is a macro of form \def\...#1...\@nil{...}
% Argument #2 is the label reference, e.g. "sect:test"
\newcommand*\@myautoref[2]{% \HyPsd@@@autoref from hyperref, modified
  \expandafter\ifx\csname r@#2\endcsname\relax
    ??%
  \else
    \expandafter\expandafter\expandafter\@@myautoref
        \csname r@#2\endcsname{}{}{}{}\@nil#1\@nil
  \fi
}
\def\@@myautoref#1#2#3#4#5\@nil#6\@nil{% \HyPsd@autorefname, modified
  #6#4.\@nil}% Argument #4 = type and number, e.g. "section.1" or "subsection.1.2"

% \myreftype results in the type name, e.g. "section" or "figure".
% The starred variant will remove a star, if existent, i.e. "section*" will become "section"
\newcommand\myreftype{%
  \@ifstar
    {\@myautoref\@@myreftype}%
    {\@myautoref\@myreftype}}
\def\@myreftype#1.#2\@nil{#1}
\def\@@myreftype#1.#2\@nil{\@@@myreftype#1*\@nil}
\def\@@@myreftype#1*#2\@nil{#1}

% \myautorefname results in the type prose name (plus space character),
% e.g. "section" in English or "Abschnitt" in German
% (like \autoref, but without number).
% \HyPsd@@autorefname is defined in the hyperref package.
\newcommand*\myautorefname[1]{\@myautoref\HyPsd@@autorefname{#1}}

% An alternative version of \myautorefname without space at the end.
% Since the \space is hard coded inside \HyPsd@@autorefname we use our
% own version called \@myautorefname instead.
% Furthermore we offer a starred variant which will work with labels to
% \section* etc., too.
\renewcommand*\myautorefname{%
  \@ifstar
    {\@myautoref\@@myautorefname}%
    {\@myautoref\@myautorefname}}
\def\@myautorefname#1.#2\@nil{% = \HyPsd@@autorefname without \space
  \ltx@IfUndefined{#1autorefname}%
    {\ltx@IfUndefined{#1name}%
      {}%
      {\csname#1name\endcsname}}%
    {\csname#1autorefname\endcsname}}
\def\@@myautorefname#1.#2\@nil{%
  \expandafter\@myautorefname\@@@myreftype#1*\@nil.\@nil}

\makeatother

\begin{document}

\myreftype{section:one}
\myreftype{subsection:one}
\myreftype{figure:one}
\myreftype{section:two}

\myreftype*{section:one}
\myreftype*{subsection:one}
\myreftype*{figure:one}
\myreftype*{section:two}

\myautorefname{section:one}
\myautorefname{subsection:one}
\myautorefname{figure:one}
\myautorefname{section:two}

\myautorefname*{section:one}
\myautorefname*{subsection:one}
\myautorefname*{figure:one}
\myautorefname*{section:two}

\section{Section One}
\label{section:one}

\subsection{Subsection One}
\label{subsection:one}

\begin{figure}
\caption{Figure One}
\label{figure:one}
\end{figure}

\section*{Section Two}
\label{section:two}

\end{document}

The code above is an extract of a solution I once wrote for a German LaTeX forum, see: http://www.mrunix.de/forums/showthread.php?t=71566

Please note that this one uses the facilities of hyperref alone. I'm not familiar with packages like varioref or cleverref, so there may be a better solution using one of those packages.

  • This works like a charm! One issue though, it seems as if \myautorefname always leaves a space after itself... is there any way of avoiding this? – mpr Nov 06 '11 at 08:09
  • Do you need \myautorefname at all? I just put it in as further example of the usage of \@myautoref. However, the extra space is hard coded as \space inside \HyPsd@@autorefname. If you don't want it you can either copy the code of \HyPsd@@autorefname, save it as \@myautorefname, remove the \space and use this instead, or you can build a wrapper macro which operates inside a group and redefines \space to \relax. I'll add the first approach to my answer right now... –  Nov 06 '11 at 08:29
  • I'm sorry, but your code fails to recognize starred versions of the command (I get section* if I call \myreftype but nothing if I call \myautorefname). Could it be possible to "ignore" the "starrification" of commands and have section* report as section? – mpr Nov 06 '11 at 15:55
  • The section* comes from the hyperref package so nothing can be done about this without patching the hyperref package itself. (I don't know why it puts section* into the AUX file but surely there is a reason for it...) If you want to \autoref and \myautorefname work with section* too, you could add the code line \expandafter\def\csname section*autorefname\endcsname{\sectionautorefname} to your document preamble. –  Nov 06 '11 at 16:36
  • I'm actually more interested in getting \myreftype to work properly since I define counters based on the return value of it. Is it not possible to remove an "optional" star from the end of a string or something like it? – mpr Nov 06 '11 at 16:59
  • Maybe \newcommand\removestar[1]{\@removestar#1*\@nil} \def\@removestar#1*#2\@nil{#1} would do the trick for you? Both \removestar{section} and \removestar{section*} will give you section. –  Nov 06 '11 at 18:33
  • ... I just added the "remove star" feature to my answer above by adding starred variants of \myreftype and \myautorefname. –  Nov 06 '11 at 19:27
  • Thank you so very much! A slight modification of your code was exactly what I was looking for :) – mpr Nov 06 '11 at 20:00