Cómo convertir una cadena leída desde un archivo (CSV) en un contador

Cómo convertir una cadena leída desde un archivo (CSV) en un contador

Tengo un archivo csv con etiquetas y números (de página), como sigue:

tag,nr
t1,1
t2,5
t3,9

La columna nr se refiere a los números de página en un archivo pdf. Cada página tiene una etiqueta correspondiente. Dada una etiqueta, quiero mostrar la página correspondiente en una figura en mi documento de látex.

Con datatools puedo cargar el archivo csv y recuperar el número de página de una etiqueta determinada. Por ejemplo, para la etiqueta t2obtengo la página número 5.

Pero ahora, cuando introduzco ese número de página como page=...argumento para incluir gráficos, aparece el mensaje de error.

"! Número faltante, tratado como cero."`

¿Qué paso adicional debo tomar para convertir la 5cadena de látex en un número de página que incluya gráficos pueda manejar?

Aquí hay una versión simplificada (que usa contadores en lugar de incluir gráficos) que desencadena el problema:

\documentclass{article}
\usepackage{datatool}

\begin{document}

\DTLloaddb{tags}{prestags.csv}
\newcommand{\pagenr}{\DTLfetch{tags}{tag}{t2}{nr}}

\newcounter{snr}
\addtocounter{snr}{\pagenr}

\end{document}

% Output:

! Missing number, treated as zero.
<to be read again> 
                   \let 
l.10 \addtocounter{snr}{\pagenr}

¿Qué debo hacer para solucionar esto?

Respuesta1

El problema es que la \DTLfetchmacro no es ampliable. Puedes utilizar la técnica que se describe aquí:

para superar esto. Aquí hay un ejemplo resuelto:

\documentclass{article}
\begin{filecontents}{\jobname.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents}
\usepackage{datatool}
\newcommand{\getvar}[1]{\DTLfetchsave{\myvar}{tags}{tag}{#1}{nr}}
\newcommand{\DTLfetchsave}[5]{%
  \edtlgetrowforvalue{#2}{\dtlcolumnindex{#2}{#3}}{#4}%
  \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#2}{#5}}%
  \let#1\dtlcurrentvalue
}
\newcounter{snr}
\begin{document}

\DTLloaddb{tags}{prestags.csv}

\setcounter{snr}{3}
The counter value is \thesnr

\getvar{t2}
\addtocounter{snr}{\myvar}
The counter value is: \thesnr

\end{document}

salida de código

Respuesta2

Aquí, uso el readarraypaquete para digerir el archivo csv y una listofitemslectura para colocar los datos en una lista. La macro \getvares ampliable.

\begin{filecontents*}[overwrite]{prestags.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents*}
\documentclass{article}
\usepackage{readarray,graphicx}
\begin{document}
\readarraysepchar{\\}
\readdef{prestags.csv}\mycsvdata
\setsepchar{\\/,}
\readlist*{\mycsvlist}{\mycsvdata}
\foreachitem\z\in\mycsvlist[]{%
  \expandafter\gdef\csname mytag\mycsvlist[\zcnt,1]\expandafter
    \endcsname\expandafter{\expandafter
    \mycsvlist\expandafter[\zcnt,2]}%
}
\newcommand\getvar[1]{\csname mytag#1\endcsname}

The t2 tag corresonds with page \getvar{t2}

\includegraphics[page=\getvar{t3},scale=.6]{readarray.pdf}
\end{document}

ingrese la descripción de la imagen aquí

Respuesta3

Si no le importa definir una macro temporal globalmente, probablemente pueda usar \DTLassignfirstmatch:

Al compilar el siguiente ejemplo, aparecen dos mensajes de error.

Esto es a propósito para que pueda ver qué sucede en caso de intentar recuperar valores no existentes.

\begin{filecontents*}{prestags.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents*}

\makeatletter
\newcommand\MyStuffDTLfetchsavePackageError[7]{%
  \PackageError{#1}{#7}{%
    In order to retrieve from database `#2`\MessageBreak
    the value of the key `#5` in the first row\MessageBreak
    where the key `#3` has value `#4`,\MessageBreak
    database `#2` must exist and have keys\MessageBreak
    `#3` and `#5` and a row where the key `#3`\MessageBreak
    has the value `#4`.%
  }%
  \global\let#6=\dtlnovalue
}%
\DeclareRobustCommand{\MyStuffDTLfetchsave}[5]{%
  %#1 = macro to store as result
  %#2 = data base name
  %#3 = key 1
  %#4 = value of key 1
  %#5 = key 2
  \@bsphack
  \DTLifdbexists{#2}{%
    \DTLifhaskey{#2}{#3}{%
      \DTLifhaskey{#2}{#5}{%
        \global\let#1=\dtlnovalue
        \DTLassignfirstmatch{#2}{#3}{#4}{#1=#5}%
        \ifx#1\dtlnovalue\expandafter\@firstofone\else\expandafter\@gobble\fi
        {%
          \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}%
             {In data base `#2' no row's key `#3' holds the value `#4'}%
        }%
      }{%
        \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}%
          {There is no key `#5' in data base `#2'}%
      }%
    }{%
      \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}%
        {There is no key `#3' in data base `#2'}%
    }%
  }{%
    \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}%
      {Data base `#2' doesn't exist}%
  }%
  \@esphack
}%
\makeatother

\documentclass{article}
\usepackage{datatool}

\newcounter{snr}

\begin{document}

\DTLloaddb{tags}{prestags.csv}

\setcounter{snr}{3}%
\noindent The counter value is: \thesnr

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t1}{nr}%
\ifx\scratchy\dtlnovalue
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t1` could not be retrieved.

  \noindent Calculations where this value would have been used were not performed.
\else
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t1` is: \scratchy

  \addtocounter{snr}{\scratchy}%
  \noindent After adding that value to the counter, the counter value is: \thesnr
\fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t2}{nr}%
\ifx\scratchy\dtlnovalue
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t2` could not be retrieved.

  \noindent Calculations where this value would have been used were not performed.
\else
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t2` is: \scratchy

  \addtocounter{snr}{\scratchy}%
  \noindent After adding that value to the counter, the counter value is: \thesnr
\fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t3}{nr}%
\ifx\scratchy\dtlnovalue
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t3` could not be retrieved.

  \noindent Calculations where this value would have been used were not performed.
\else
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t3` is: \scratchy

  \addtocounter{snr}{\scratchy}%
  \noindent After adding that value to the counter, the counter value is: \thesnr
\fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t4}{nr}%
\ifx\scratchy\dtlnovalue
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t4` could not be retrieved.

  \noindent Calculations where this value would have been used were not performed.
\else
  \noindent The value of the key `nr` in the row where the key `tag` has the value `t4` is: \scratchy

  \addtocounter{snr}{\scratchy}%
  \noindent After adding that value to the counter, the counter value is: \thesnr
\fi

\end{document}

ingrese la descripción de la imagen aquí

Respuesta4

Como lo sugiere@cabohah, la DTLfetchlínea de la pregunta se puede reemplazar por las dos líneas siguientes:

\DTLgetlocation{\rownr}{\colnr}{tags}{t2}
\DTLgetvalue{\pagenr}{tags}{\rownr}{\dtlcolumnindex{tags}{nr}}

Como se trataba de un cambio simple, esto es lo que terminé usando.

información relacionada