14

Sometimes I want to refer to a long list of tables or figures. I've labelled them in categorical ways, but it's a lot of typing (I'm lazy programmer) to type out something like:

\ref{tab:foo1}, \ref{tab:foo2}, \ref{tab:foo3}, \ref{tab:foo4}

the ideal result of which looks like :

1, 2, 3, 4

Wouldn't it be nice if I could just use regexes here instead? That is:

\ref{tab:foo.*}

Or, even better :

\ref{tab:foo[0-9]*}

I'm not very hopeful that this exists. I'm mostly just curious : Does anyone know of a package that enables this?

15

The l3regex module of LaTeX3 can be beneficial.

You use \lazylabel for labeling the objects and \lazyref with a regex as its argument.

Actually there is support for "classes" of labels, which is left as an exercise.

Consult the documentation of l3regex for checking the precise syntax of regular expressions.

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn

\seq_clear_new:N \g_lazylabel_alllabels_seq
\seq_new:N \l_lazylabel_temp_seq

\NewDocumentCommand{\lazylabel}{O{alllabels}m}
 {
  \label{#2}
  \seq_if_in:cnF { g_lazylabel_#1_seq } { #2 }
   { \seq_gput_right:cn { g_lazylabel_#1_seq } { #2 } }
  \iow_shipout:cn { @auxout } { \newlazylabel { #1 } { #2 } }
 }
\cs_generate_variant:Nn \iow_shipout:Nn { c }

\NewDocumentCommand{\newlazylabel}{m m}
 {
  \seq_if_exist:cF { g_lazylabel_#1_seq }
   { \seq_new:c { g_lazylabel_#1_seq } }
  \seq_if_in:cnF { g_lazylabel_#1_seq } { #2 }
   { \seq_gput_right:cn { g_lazylabel_#1_seq } { #2 } }
 }

\NewDocumentCommand{\definelabelclass}{m}
 {
  \seq_clear_new:c { g_lazylabel_#1_seq }
 }

\NewDocumentCommand{\lazyref}{O{alllabels} m}
 {
  \lazylabel_extract:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \lazylabel_extract:nn #1 #2
 {
  \seq_clear:N \l_lazylabel_temp_seq
  \seq_map_inline:cn { g_lazylabel_#1_seq }
   {
    \regex_match:nnT { #2 } { ##1 } 
     {
      \seq_put_right:Nn \l_lazylabel_temp_seq { \ref{##1} }
     }
   }
  \seq_use:Nnnn \l_lazylabel_temp_seq { ~and~ } { ,~ } { ~and~ }
 }
\ExplSyntaxOff

\begin{document}

In sections \lazyref{sec:*} \dots


\section{a}\lazylabel{sec:a}
\section{b}\lazylabel{sec:b}
\begin{table}
\caption{a}\lazylabel{tab:foo}
\caption{a}\lazylabel{tab:foo1}
\caption{a}\lazylabel{tab:foo2}
\caption{a}\lazylabel{tab:bar1}
\end{table}


See tables \lazyref{tab:foo[1-9]+}

\end{document}

enter image description here

|improve this answer|||||
  • 1
    Wow, that should go to CTAN verbatim. – mafp Mar 26 '13 at 14:52
  • Remarkably (to me at least!), the \lazylabels and \lazyrefs even play nicely with hyperref. – Mico Mar 26 '13 at 16:22
  • @Mico I use only the standard \label and \ref for establishing the cross references. :) – egreg Mar 26 '13 at 16:54
  • What's so neat is that the translation from \lazy[label,ref] to the ordinary commands is taken care of so well. – Mico Mar 26 '13 at 17:21
  • This is awesome. I'm actually a little startled that there was an answer. I'm glad to find I'm not the only person who has ever wanted this feature! – katyhuff Mar 27 '13 at 16:49
9

TeX and LaTeX aren't set up very well to "do" regular expressions, at least not without a lot of extra programming. However, you may be in luck nevertheless: the cleveref package may do what you're looking to do.

For instance, the command

\crefrange{tab:foo1}{tab:foo4}

will typeset Tables 1 to 4; this assumes, of course, that the table labeled {tab:foo1} is numbered 1 and that the table labeled {tab:foo4} is numbered 4. If instead they're numbered 22 and 25, the command \crefrange{tab:foo1}{tab:foo4} will generate Tables 22 to 25.

The \crefrange command is appropriate if the first and last labels point to items (here: tables, right?) that are numbered consecutively. If that's not the case, you could use the command

\cref{tab:foo1,tab:foo2,tab:foo3,tab:foo4}

and let the cleveref package do the job of sorting and (if necessary) compressing the references. For instance, if the four tables are numbered 3, 4, 5, and 8, the \cref command above will generate Tables 3 to 5 and 8. If you do not want compression of consecutive numbers, be sure to load the package with the option [sort]; this will result in the following typeset output: Tables 3, 4, 5 and 8.

If, for some reason, you do not want to include the cross-referenced items' "name" (here: Table) in the cross-reference -- presumably because you would want to supply it yourself -- you could use the command \labelcref instead of \cref.

Finally, if you use the hyperref package as well, be sure to load cleveref after hyperref.

|improve this answer|||||
  • It was really hard to decide which one of these was what I wanted. Sorry to pick the other answer. Yours is great! Thanks! – katyhuff Mar 27 '13 at 16:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.