TransWikia.com

How to convert the last number of the ref command output to string

TeX - LaTeX Asked on January 25, 2021

There is an answer explaining how to convert numbers to text here. But if I use a ref output in the command convertdigits, it throws the error Missing number, treated as zero. even if the ref output is a one-digit number. The code below is taken from that site.

documentclass{article}

makeatletter
newcommand{convertdigits}[1]{expandafterconvert@digits#1convert@digits}
defconvert@digits#1{%
  ifx#1convert@digits
    expandafter@gobble
  else
    expandafter@firstofone
  fi
  {convert@@digits#1}%
}
defconvert@@digits#1{%
  ifnum9=9#1%
    expandafter@gobble
  else
    expandafter@firstofone
  fi
  {convert@@digit#1}convert@digits
}
defconvert@@digit#1{%
  ifcase#1%
    zeroor
    oneor
    twoor
    threeor
    fouror
    fiveor
    sixor
    sevenor
    eightor
    ninefi
}
makeatother

begin{document}
section{a}
subsection{a1}label{key}
subsection{a2}
section{b}
subsection{b1}
subsection{b2}
subsubsection{b3}
ref{key}

defmyvar{2}

convertdigits{2}

convertdigits{myvar}

convertdigits{ref{key}} % ERROR

end{document}

My question: Can I convert the last digit of the ref{key} to string.
For example, if

the output of ref{key} is 2.3

then

the output of convertdigits{ref{key}} should be three.

3 Answers

You can use the macro getrefbykeydefault from the refcount-package for extracting that sequence of tokens that yield the text-string of the reference.

Assuming that expansion will not significantly change that sequence, you can take these tokens for a list of .-separated elements and extract the last one thereof. (When writing "significantly change that sequence" I think about scenarios like expansion leading to the removal of some of the dot-separated elements.)

If it is ensured that expanding the last dot-separated element yields only a valid ⟨number⟩-quantity denoting a non-negative number, it can be "fed", e.g, to the numberstringnum-macro of the fmtcount-package.

With the example below checking whether expanding it yields only a valid TeX-⟨number⟩-quantity denoting a non-negative number is omitted because no such test is known to me which is not flawed in some way.

(Any such test must be flawed/ will work out only for some restricted subset of possible user-input:

When attempting to implement an algorithm for such a test, then you are facing the halting-problem:

At the time of expanding them, the tokens forming the last dot-separated element of the text-string of the reference may form an arbitrary expansion-based algorithm. Having an algorithm check whether such an algorithm in the end yields a valid TeX-⟨number⟩-quantity (denoting a non-negative number) implies having an algorithm check whether an other arbitrary algorithm terminates at all/terminates without error-messages. This is the halting-problem. Alan Turing proved that it is not possible to implement an algorithm which for any arbitrary algorithm can "decide" whether that algorithm will ever terminate.)

documentclass{article}
usepackage{hyperref}
usepackage{refcount}
usepackage{fmtcount}

makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
newcommandUD@CheckWhetherNull[1]{%
  romannumeral0expandafter@secondoftwostring{expandafter
  @secondoftwoexpandafter{expandafter{string#1}expandafter
  @secondoftwostring}expandafter@firstoftwoexpandafter{expandafter
  @secondoftwostring}@firstoftwoexpandafter{} @secondoftwo}%
  {@firstoftwoexpandafter{} @firstoftwo}%
}%
%-------------------------------------------------------------------------
@ifdefinableUD@gobbletofirstdot{longdefUD@gobbletofirstdot#1.{}}%
@ifdefinableUD@keeptofirstdot{longdefUD@keeptofirstdot#1.{#1}}%
newcommandUD@PassFirstToSecond[2]{#2{#1}}
newcommandextractlastdotitem[3]{romannumeral0extractlastdotitemloop{#1.}{#2}{#3}}%
newcommandextractlastdotitemloop[3]{%
  expandafterUD@CheckWhetherNullexpandafter{UD@gobbletofirstdot#1}{%
    expandafterexpandafterexpandafterUD@PassFirstToSecond
    expandafterexpandafterexpandafter{expandafter@gobbleUD@keeptofirstdotrelax#1}{ #2}#3%
  }{%
    expandafterextractlastdotitemloopexpandafter{UD@gobbletofirstdot#1}{#2}{#3}%
  }%
}%
newcommandconvertdigitsoflabel[1]{%
  IfRefUndefinedBabel{#1}{@ifundefined{hyperref}{ref}{ref*}{#1}}{%
    begingroupprotected@edef@tempa{getrefbykeydefault{#1}{}{0}}%
    expandafterextractlastdotitemexpandafter{@tempa}{endgroupnumberstringnum}{[m]}%
   }%
}%
makeatother


begin{document}
section{a}
subsection{a1}label{a1}
subsection{a2}
subsection{a3}
subsection{a4}
subsection{a5}
subsection{a6}
subsection{a7}
subsection{a8}
subsection{a9}
subsection{a10}
subsection{a11}label{a11}
section{b}
subsection{b1}
subsection{b2}
subsubsection{b3}

bigskiphrulebigskip

ref{a1}

ref{a11}

convertdigitsoflabel{a1}

convertdigitsoflabel{a11}

hyperref[{a1}]{convertdigitsoflabel{a1}}

hyperref[{a11}]{convertdigitsoflabel{a11}}

end{document}

enter image description here

Answered by Ulrich Diez on January 25, 2021

You can use refcount and its expandable getrefnumber.

In order to isolate the final part of the input string, you can use regex_split:nnN that will store the parts separated by periods into different items of a sequence and take the last item.

documentclass{article}
usepackage{xparse}
usepackage{refcount}

ExplSyntaxOn

NewDocumentCommand{convertdigits}{m}
 {
  mert_convertdigits:e { #1 }
 }

cs_new_protected:Nn mert_convertdigits:n
 {
  regex_split:nnN { . } { #1 } l__mert_convertdigits_seq
  __mert_digit:e { seq_item:Nn l__mert_convertdigits_seq { -1 } }
 }
cs_generate_variant:Nn mert_convertdigits:n { e }

cs_new:Nn __mert_digit:n
 {
  str_case:nnF { #1 }
   {
    {0}{zero}
    {1}{one}
    {2}{two}
    {3}{three}
    {4}{four}
    {5}{five}
    {6}{six}
    {7}{seven}
    {8}{eight}
    {9}{nine}
   }
   {#1}% not a digit
 }
cs_generate_variant:Nn __mert_digit:n { e }

ExplSyntaxOff

begin{document}

section{a}
subsection{a1}label{key}
subsection{a2}
section{b}
subsection{b1}
subsection{b2}label{key2}
subsubsection{b3}

ref{key}, ref{key2}

defmyvar{2}

convertdigits{2}

convertdigits{myvar}

defmyvar{2.3}

convertdigits{myvar}

convertdigits{getrefnumber{key}}

convertdigits{getrefnumber{key2}}

end{document}

enter image description here

If you want to continue to use ref in that context, you can change the main definition to

NewDocumentCommand{convertdigits}{m}
 {
  group_begin:
  cs_set_eq:NN ref getrefnumber
  mert_convertdigits:e { #1 }
  group_end:
 }

Answered by egreg on January 25, 2021

You can do something like this:

{defhbox#1{}defprotect#1empty{??}xdefreftext{ref{key}empty}}
convertdigits{reftext}

Answered by wipet on January 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP