5

I need to measure a number of characters in string, that I returned from label through \nameref command.

Here is my MWE:

\documentclass{article}

\usepackage{hyperref}
\usepackage{xstring}

\begin{document}

\protected\def\testStr{\nameref{testLabel}}
String content = \testStr
\par

\newlength\testStrWidth
\settowidth{\testStrWidth}{\testStr}
String width = \the\testStrWidth
\par

\StrLen{\testStr}[\testStrNumOfChars]
Number of characters in string = \testStrNumOfChars

\clearpage

\makeatletter
\edef\@currentlabelname{This is a somewhat long string}
\label{testLabel}
\makeatother

Here we have some text to make another page.

\end{document}

Here is the result:

MWE result

MWE doesn't give any errors. I'm using XeTeX, but it doesn't work in pdfLaTeX too. I've tried \edef, \def, \let instead of \protected\def, but nothing seems to work.

Of course, if I set tested string explicitly inside \StrLen command, everything will work as it should.

Any help would be much appreciated.

Werner
  • 603,163

2 Answers2

4

You need an expandable version of \nameref:

\documentclass{article}

\usepackage{xstring}
\usepackage{hyperref}

\makeatletter
\newcommand{\getnamereftext}[1]{%
  \@ifundefined{r@#1}{}{%
    \unexpanded\expandafter\expandafter\expandafter{%
      \expandafter\expandafter\expandafter\@thirdoffive\csname r@#1\endcsname
    }%
  }%
}

\begin{document}

\StrLen{\getnamereftext{testLabel}}[\testStrNumOfChars]
Number of characters in string = \testStrNumOfChars

\makeatletter
\edef\@currentlabelname{This is a somewhat long string}
\label{testLabel}
\makeatother

\end{document}

This will return 0 when the label is not yet defined.

enter image description here

egreg
  • 1,121,712
  • I really need the use of \getnamereftext but it seems to add white spaces to the beginning of the string. How can I prevent this? – Felipe Apr 27 '20 at 03:40
  • @Felipe Check for unprotected end-lines in your code – egreg Apr 27 '20 at 07:28
4

The \nameref command needs to be fully expanded into its textual form. To that end, you need to remove the hyperlinking that surrounds it, as that is what's causing the problems.

The following is marginally different from egreg's answer and uses e-TeX for conditioning on the existence of the reference - \r@<label>. All we're interested in is extracting the name/title. Nothing more...

enter image description here

\documentclass{article}

\usepackage{hyperref,xstring}
\newcommand{\thirdoffive}[5]{#3}% Similar to \@thirdoffive
% \assignnameref{<ref>}{<macro>}
\newcommand{\assignnameref}[2]{%
  \gdef#2{}% Assign macro to be blank
  \ifcsname r@#1\endcsname % If the reference exists...
    \xdef#2{\expandafter\expandafter\expandafter\thirdoffive\csname r@#1\endcsname}% ...grab the third argument - the name/title
  \fi
}
\begin{document}

\assignnameref{testLabel}{\testStr}%
String content = \testStr
\par

\newlength\testStrWidth
\settowidth{\testStrWidth}{\testStr}%
String width = \the\testStrWidth
\par

\StrLen{\testStr}[\testStrNumOfChars]%
Number of characters in string = \testStrNumOfChars

\clearpage

\makeatletter
\edef\@currentlabelname{This is a somewhat long string}
\label{testLabel}
\makeatother

Here we have some text to make another page.

\end{document}

Yes, \labels exist in the .aux file as macros in the form \r@<label> (via \newlabel). See Understanding how references and labels work.

Werner
  • 603,163
  • Thanks for replay! So I can extract even another label attributes through this method. It will be really useful. – Andrei Borisov Mar 01 '16 at 01:31
  • @AndrewBohr: Yup. Based on hyperref, the first attribute is the reference number, the second attribute is the page number, the third attribute is the title, the fourth attribute is the hyperlink anchor, while the fifth attribute is left blank. – Werner Mar 01 '16 at 01:46