40

Is it possible to define a directive which creates a custom label which I can later reference on multiple locations with \ref{...}?

For example:

...
\createlabel{l-foo}{22}
...
% later in document:
In line \ref{l-foo} foo-bar. Furthermore, line \ref{l-foo}...
...

Should get translated into:

In line 22 foo-bar. Furthermore, line 22...

Alternatively, is there a way to define a set of predefined values somewhere in the beginning of the document (it doesn't have to be the label mechanism) so that I can later use them in the text.

3
  • \label refers to the last \refstepcounter{<counter>}. If you use your own counter like that than it isn't a problem. Numbering every line is a different challenge. Commented May 13, 2011 at 21:45
  • I was using the lineno package to do line numbering, but defining labels based on line numbers within figure environments doesn't work there. I would settle with defining the line numbers for the labels manually in some way - just so that if something changes, I only have to update the label definitions, and not the refs too. If there is some other, non-label related way to do it, I would be satisfied with that as well.
    – axel22
    Commented May 13, 2011 at 21:50
  • 1
    You could use a counter which you set to your manual value - 1 and then use \refstepcounter{...} followed by a \label. This would cause proper references I think. Also have a look on the zref package. It provides a wide variety of referencing features. Commented May 13, 2011 at 21:56

8 Answers 8

26

Do you really need to use \ref? You could just say \newcommand{\foobar}{22}, so that when you type \foobar you get 22. Of course this crude approach does not work if any references occur before the label is defined. To do it with \ref, try this.

\documentclass{minimal}
\makeatletter
\newcommand{\customlabel}[2]{%
\protected@write \@auxout {}{\string \newlabel {#1}{{#2}{}}}}
\makeatother
\begin{document}
Here is some text. \customlabel{foobar}{22}
Here is some more text \ref{foobar}.
\end{document} 
7
  • Brilliant - not only does this work, but it also creates a label inside figure environments, which can be referenced outside of them. This means that I can take lineno's directive \LineNumber and use it to generate a line number within a figure - like this: \customlabel{labelname}{\LineNumber}. Thanks a lot!
    – axel22
    Commented May 13, 2011 at 22:22
  • 4
    It does not work for me. I get the following error Paragraph ended before \Hy@setref@link was complete.
    – Gastón
    Commented Jan 6, 2012 at 3:49
  • @Mario --- Under what circumstances? The example works fine for me. Commented Jan 6, 2012 at 17:21
  • @Ian Perhaps the reason is that I'm using KOMA...
    – Gastón
    Commented Jan 8, 2012 at 4:59
  • 3
    @Mario --- I think it's the hyperref package. I do not know how to fix this. Ask a new question and someone will sort out the problem (or suggest an alternative solution). Commented Jan 8, 2012 at 22:55
49
+200

I found a solution for the custom label what works with hyperref, been looking everywhere and I keep ending back to this page. (By google searching)

Solution by Ian (does not work with hyperref)

\makeatletter
\newcommand{\customlabel}[2]{%
\protected@write \@auxout {}{\string \newlabel {#1}{{#2}{}}}}
\makeatother

The reason it does not work with hyperref, is that the package change the \newlabel command so it has 6 parameters.

Modified version of Ian's answer, that works with hyperref package.

\makeatletter
\newcommand{\customlabel}[2]{%
   \protected@write \@auxout {}{\string \newlabel {#1}{{#2}{\thepage}{#2}{#1}{}} }%
   \hypertarget{#1}{#2}
}
\makeatother

However doing this means that the modified version requires hyperref package.

\hypertarget is added to make the links work when using \ref.

13
  • 4
    The second works well, but using \customlabel{refname}{displaytext} puts the displaytext also where \customlabel is called. Do you know how to get rid of that text? Commented Feb 4, 2015 at 21:52
  • 8
    @barto: The second argument to \hypertarget is the culprit; using \hypertarget{#1}{} seems to work perfectly. Commented Apr 22, 2015 at 16:26
  • 1
    @HenrikBøgelundLavstsen: Can you mention what the arguments to hyperref's redefined version of \newlabel are, or where this is documented? By the way, I am giving you a bounty for this answer. Thanks! Commented Apr 22, 2015 at 16:43
  • 1
    @FilippoAlbertoEdoardo No sorry. When i looked this up i just checked in the hyperref source files, and found the newlabel with overridden there. Commented Oct 15, 2019 at 7:48
  • 2
    The modified version adds a space character after the second argument for me. Writing \hypertarget{#1}{#2}% instead of \hypertarget{#1}{#2} resolved this issue. Commented May 14, 2020 at 15:53
2
\documentclass{article}

\usepackage{lineno}

\begin{document}

\linenumbers

\modulolinenumbers[255] % To switch off the showing of the numbers on margins

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus
elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur
dictum gravida mauris. \linelabel{line:Nam}Nam arcu libero,
nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula
augue eu neque. Pellentesque habitant morbi tristique senectus et
netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras
viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla
ultrices.  Phasellus eu tellus sit amet tortor gravida placerat.
Integer sapien est, iaculis in, pretium quis, viverra ac, nunc.
Praesent eget sem vel leo ultrices bibendum.  Aenean faucibus.  Morbi
dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla.  Curabitur
auctor semper nulla. Donec varius orci eget risus. Duis nibh mi,
congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit
amet orci dignissim rutrum

The sentence ``Nam arcu libero'' starts at line~\ref{line:Nam}

\end{document}
1
  • Thanks! I was aware of the \linelabel directive, unfortunately, it does not work within figure environments, even if you use \internallinenumbers in the beginning.
    – axel22
    Commented May 13, 2011 at 22:23
2

I guess the shortest solution is to use \def:

\documentclass[a4paper,oneside,11pt]{report}

\def \lfoo {22 }

\begin{document}
    In line \lfoo foo-bar. Furthermore, line \lfoo...
\end{document}

enter image description here

1

what about this:

\makeatletter
\newcommand{\mylabel}[2]{%
 \@bsphack\begingroup
 \def\@currentlabel{#2}%
 \label{#1}%
 \endgroup\@esphack
}
\makeatother

another example - define custom labels for a new environment:

\makeatletter%
\newenvironment{myenvironment}{%
 \addtocounter{mycounter}{1}%
 \def\@currentlabel{{\thesection.\themycounter}}%  custom labelling for this environment
 %%... etc.,  other environment definitions here
}{%
%...
}
\makeatother
1
1

I am not sure I understand. I think this answer the question (no use of aux file)

Edit: as mentioned below by egreg this work only if \refis called after \createlabel

\documentclass{article}
\makeatletter
\newcommand{\createlabel}[2]{%
\@bsphack
\expandafter\edef\csname #1\endcsname{#2}\@esphack}
\makeatother
\newcommand{\Ref}[1]{\csname #1\endcsname}
\begin{document}
test
\createlabel{l-foo}{22} and leater \Ref{l-foo}
\end{document}
2
  • Then \Ref can only be used after the corresponding \createlabel command.
    – egreg
    Commented Apr 22, 2015 at 17:47
  • @egreg as i said may be i don't undestand but it was clear for me that it will be call later no?
    – touhami
    Commented Apr 22, 2015 at 17:49
1

Hyperref-proof solution (1. works with hyperref, 2. also adds hyperlinks to the \xlabel):

You can use \nameref which is part of hyperref :

\documentclass{article}

\usepackage{hyperref}
\newcommand{\xref}{\nameref}
\makeatletter
\newcommand\xlabel[2][]{\phantomsection\def\@currentlabelname{#1}\label{#2}}
\makeatother

\begin{document}

We call $t$ {\em positive}\xlabel[positive]{pos} if $t>0$. Now ...

\bigskip

Assume that $s$ is \xref{pos}. Then ...

Recall the definition of \hyperref[pos]{positivity}

\end{document}

Now \xref{pos} prints "positive" with a hyperlink to the definition (xlabel). (The \hyperref above prints the customized text "positivity" instead of "positive". To produce hyperlinks without )

To avoid repetition, you can just write \emxlabel{positive}{pos} above once you define:

\newcommand{\emxlabel}[2]{{\em #1}\xlabel[#1]{#2}}

Similarly, you can use the following for itemized lists:

\newcommand{\itempxlabel}[1]{\item[\bf (#1)]\xlabel[(#1)]{#1}} 

To make the [first argument] equal to the {second} if not given, use this code (or see here):

\usepackage{xifthen}
\makeatletter
\newcommand{\xlabel}[2][]{\phantomsection\def\@currentlabelname{\ifthenelse{\equal{#1}{}}{#2}{#1}}\label{#2}} 
\makeatother

More sophisticated systems are possible with packages like glossaries or acronym. The above solution is essentially due to Ulrike Fischer.

Benefits:

  1. You can change the appearance of the \xref{pos} later on just by changing the first argument of \xlabel. (Also the other solutions have this benefit except that some of them stop working if you \usepackage{hyperref}.)
  2. \xref{pos} also produces a hyperlink. By clicking it you get to the definition (\xlabel). TexShop also shows a hover (mouseover) text (the definition). I don't know how to get the hovertext to TeXStudio.

Add the following lines to your .cwl file (and restart TeXstudio) to allow for auto-completion of \xref label (and to include \xlabel labels etc. into that list):

\xref{label}#r
\xlabel{label}#l
\itempxlabel{label}#l
\emxlabel{label}#l

If you use the {xifthen} formulation of \xlabel, then its .cwl line shoud read

\xlabel[nonlabel]{label}#l 
2
  • Thanks, works excellently well. Commented Jun 26, 2021 at 20:30
  • Thanks. I guess the only con is: you must always use \xref, you cannot use \ref for labels created by \xlabel (or the other labels created above). It would be easier if you would not have to remember, which are standard labels and which are xlabels. But I have had no problems with this "con".
    – Convexity
    Commented Jul 24, 2021 at 8:05
0

If you use the cleveref package, you can also use the \crefname command and then use an optional argument in the \label command.

The following example is borrowed from Mico from here:

\documentclass{article}
\usepackage[colorlinks=true]{hyperref}
\usepackage[nameinlink]{cleveref}    
% provide singular and plural names of the categories "car" and "truck"
\crefname{truck}{truck}{trucks}
\crefname{car}{car}{cars}

\begin{document}
\section{Section One}\label[car]{sec:1}
\section{Section Two}\label[truck]{sec:2}
\section{Section Three}
Cross-references to \cref{sec:1,sec:2}.
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .