2

I am writing a collection of documents in book form, one each for 4-5 topics. Each book has upwards of 30 chapters each in a different file. The books must be able to cross reference each other since they all are intended for the same end purpose. In every book, some of the chapters are independent of other chapters and can be rearranged at a later date. Obviously chapter number in labels is useless. I want string based label keys for each chapter/section of each book. I cannot manually generate all those keys with a consistent naming scheme.

I use a regex based string compactifier for this purpose. Not being an expert on TeX/LaTeX, this forum has been of great help to me (Unsigned integer variable in a regex). Each chapter should get a label of the form math:mod:first_chapter and sections should be labeled math:sec:first_chapter:section_name. A custom chapter/section command is used for automatic labeling.

In my MWE, I am just including the case for chapters.

\documentclass{book}
\usepackage{etoolbox,xparse,expl3,l3regex}
\usepackage[outer]{showlabels}

\ExplSyntaxOn
\NewDocumentCommand{\compactlabel}{O{20}m}
{
    \tl_set:Nn \l_tmpa_tl { #2 }
    \regex_replace_all:nnN {[^a-zA-Z\s]} {} \l_tmpa_tl
    \regex_replace_all:nnN {\b[a-zA-Z]{1,2}\b} {} \l_tmpa_tl
    \regex_replace_once:nnN {\A\s+} {} \l_tmpa_tl
    \regex_replace_once:nnN {\s+\Z} {\ } \l_tmpa_tl
    \regex_replace_all:nnN {\s+} {_} \l_tmpa_tl
    \regex_replace_all:nnN {(^\w{1,#1})\w*} {\1} \l_tmpa_tl
    \regex_replace_once:nnN {_\Z} {} \l_tmpa_tl
    \tl_set:Nx \l_tmpa_tl { \str_lower_case:f { \tl_use:N \l_tmpa_tl } }
    \tl_use:N \l_tmpa_tl
}
\ExplSyntaxOff

\ExplSyntaxOn
\cs_set_eq:NN \explower \tl_lower_case:n
\ExplSyntaxOff

\newcommand{\subjectshort}{Compsci} % unique for each book
\newcommand{\chaplabel}[1]{
    \expandafter\label\expandafter{\explower{\subjectshort}:mod:#1} % works but not desirable
    %\expandafter\label\expandafter{\explower{\subjectshort}:mod:\chaplabel{#1}} % does not work but desirable
}

\newcommand{\mychapter}[1]{ \chapter{#1} \chaplabel{#1}}

\begin{document}

\mychapter{First Chapter}

Some text
\end{document}

While creating labels, compacted names do not work. I have tried using multiple \expandafters and \detokenize to get it work. I always get the error : missing endcsname in the aux file. It is driving me crazy. What is going wrong here? How do I make it work? Any help would be appreciated.

  • Imho such automatic labels are nonsense. If you decide e.g. to translate your book and change "First Chapter" to "Premier chapitre" all your references will fail. Using the chapter text for automatic labels is for the same reason useless as in your argument against numbers: it is not stable enough. Better write some macro for your editor which creates a \label when you insert \chapter the first time. – Ulrike Fischer Jun 23 '17 at 12:13
  • I agree: an automatic label is the same as no label as far as the user is concerned. There are uses for automatic labeling, but just for internal workings of macros the user has no control upon. – egreg Jun 23 '17 at 12:29
  • why use such a complicated scheme? if you obfuscate the label generation in this way you need to use the same obfuscation every time you use \ref why not simply use a normal \abel or if that is really inconvenient, just use the entire section title. – David Carlisle Jun 23 '17 at 14:15
  • I do not contest that it is a massive overkill. However it is not useless since I frequently forget to label a section (or chapter) and when I need it, have to hastily cook up a unique label. This hasty label often has names like hamiltonxxtt, which is impossible to remember and can be used only with tools like \usepackage{showlabels}. I am anyway going to have a proliferation of labels so I might as well label each and every section even if it is an overkill. – magguu Jun 23 '17 at 15:43
  • @Magguu but why obfuscate the label so much that you would need a function to generate the \ref why not just use the section title? – David Carlisle Jun 23 '17 at 18:09
2

You might do like follows, but I don't think this is really useful.

\documentclass{book}
\usepackage{expl3,xparse}
%\usepackage{l3regex} % not for releases after June 2017
\usepackage[outer]{showlabels}

\ExplSyntaxOn
\NewDocumentCommand{\generatechapterlabel}{O{20}m}
 {
  \magguu_compactlabel:nn { #1 } { #2 }
  \label{\str_lower_case:f { \subjectshort }:mod:\l_magguu_compactlabel_tl}
  \tl_gset_eq:NN \g_magguu_currentchapterlabel_tl \l_magguu_compactlabel_tl
 }
\NewDocumentCommand{\generatesectionlabel}{O{20}m}
 {
  \magguu_compactlabel:nn { #1 } { #2 }
  \label
   {
    \str_lower_case:f { \subjectshort } : sec :
    \g_magguu_currentchapterlabel_tl :
    \l_magguu_compactlabel_tl
   }
 }

\tl_new:N \l_magguu_compactlabel_tl
\tl_new:N \g_magguu_currentchapterlabel_tl

\cs_new_protected:Nn \magguu_compactlabel:nn
 {
  \tl_set:Nn \l_magguu_compactlabel_tl { #2 }
  % remove non alphabetic/space characters
  \regex_replace_all:nnN {[^a-zA-Z\s]} {} \l_magguu_compactlabel_tl
  % remove words less than three letter long
  \regex_replace_all:nnN {\b[a-zA-Z]{1,2}\b} {} \l_magguu_compactlabel_tl
  % remove leading spaces
  \regex_replace_once:nnN {\A\s+} {} \l_magguu_compactlabel_tl
  % remove trailing spaces
  \regex_replace_once:nnN {\s+\Z} {\ } \l_magguu_compactlabel_tl
  % change runs of space into an underscore
  \regex_replace_all:nnN {\s+} {_} \l_magguu_compactlabel_tl
  % truncate to #1 characters
  \regex_replace_all:nnN {(^\w{1,#1})\w*} {\1} \l_magguu_compactlabel_tl
  % remove a possible trailing underscore
  \regex_replace_once:nnN {_\Z} {} \l_magguu_compactlabel_tl
  % lowercase the string
  \tl_set:Nx \l_magguu_compactlabel_tl { \str_lower_case:f { \tl_use:N \l_magguu_compactlabel_tl } }
}
\ExplSyntaxOff

\newcommand{\subjectshort}{Compsci} % unique for each book

\newcommand{\mychapter}[1]{\chapter{#1}\generatechapterlabel{#1}}
\newcommand{\mysection}[1]{\section{#1}\generatesectionlabel{#1}}

\textwidth=5cm % just to see the labels

\begin{document}

\mychapter{First Chapter}

Some text in chapter~\ref{compsci:mod:first_chapter}

\mysection{First Section}

Some text in section~\ref{compsci:sec:first_chapter:first_section}

\end{document}

enter image description here

| improve this answer | |
  • This is just perfect. Thanks a lot. Let me say again - this overkill is NOT useless for me. Actually I do not really understand the expl3 syntax but I just summoned up the cargo cult spirit in me and copy pasted it :) – magguu Jun 23 '17 at 15:45
  • @Magguu The compact version of the current chapter title is saved in a token list that can be used for sections; it will only change at the next \mychapter command. – egreg Jun 23 '17 at 15:52

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.