6

In the following example \DTLgetvalueforkey retrieves the information without problem, while \DTLfetch fails:

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents*}{data.csv}
Heading A, Heading B, Heading C
One,    Een,  1
Two,    Twee, 2
T_hree, Drie, 3
Four,   Vier, 4
\end{filecontents*}

\usepackage{datatool}

\begin{document}

\DTLloadrawdb
  [keys={HeadA,HeadB,HeadC}]
  {data}{data.csv}

\DTLdisplaydb{data}

\bigskip

% \DTLgetvalueforkey{<cmd>}{<key>}{<db name>}{<ref key>}{<ref value>}
% \DTLfetch{<db name>}{<col1 name>}{<col1 value>}{<col2 name>}

\textbf{Heading A} = `Two' corresponds to \textbf{Heading B} =
\DTLgetvalueforkey{\datavalue}{HeadB}{data}{HeadA}{Two}\datavalue% Twee

\textbf{Heading A} = `Two' corresponds to \textbf{Heading B} =
\DTLfetch{data}{HeadA}{Two}{HeadB}% Twee

\textbf{Heading A} = `T\_hree' corresponds to \textbf{Heading B} =
\DTLgetvalueforkey{\datavalue}{HeadB}{data}{HeadA}{T\_hree}\datavalue% Drie

% Should be the same as above, but not found
\textbf{Heading A} = `T\_hree' corresponds to \textbf{Heading B} =
\DTLfetch{data}{HeadA}{T\_hree}{HeadB}% Drie

\end{document}

Why is this? Can \DTLfetch be fixed to work here?

The problem is specific to the use of _ inside CSV entries. The input I'm working with contains this, so there's very little I can do to remove it.

Werner
  • 603,163

1 Answers1

6

The datatool user guide mentions the following about \DTLfetch:

\DTLfetch{<db name>}{<col1 name>}{<col1 value>}{<col2 name>}

This fetches and displays the value for <col2 name> in the first row where the value of <col1 name> is <col1 value>. (Note that all arguments are expanded.)

Expansion here is causing the issue. To get around this, fetch for T\noexpand\_hree rather than T\_hree:

enter image description here

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents*}{data.csv}
Heading A, Heading B, Heading C
One,    Een,  1
Two,    Twee, 2
T_hree, Drie, 3
Four,   Vier, 4
\end{filecontents*}

\usepackage{datatool}

\begin{document}

\DTLloadrawdb
  [keys={HeadA,HeadB,HeadC}]
  {data}{data.csv}

\DTLdisplaydb{data}

\bigskip

% \DTLgetvalueforkey{<cmd>}{<key>}{<db name>}{<ref key>}{<ref value>}
% \DTLfetch{<db name>}{<col1 name>}{<col1 value>}{<col2 name>}

\textbf{Heading A} = `Two' corresponds to \textbf{Heading B} =
\DTLgetvalueforkey{\datavalue}{HeadB}{data}{HeadA}{Two}\datavalue% Twee

\textbf{Heading A} = `Two' corresponds to \textbf{Heading B} =
\DTLfetch{data}{HeadA}{Two}{HeadB}% Twee

\textbf{Heading A} = `T\_hree' corresponds to \textbf{Heading B} =
\DTLgetvalueforkey{\datavalue}{HeadB}{data}{HeadA}{T\_hree}\datavalue% Drie

\textbf{Heading A} = `T\_hree' corresponds to \textbf{Heading B} =
\DTLfetch{data}{HeadA}{T\noexpand\_hree}{HeadB}% Drie

\end{document}

If you are searching based on content within a macro, as in

\def\Three{T\_hree}
\DTLfetch{data}{HeadA}{\Three}{HeadB}% Drie

you will still have a problem. Here you still need to avoid the expansion of \_. You can do this using grouping a \letting \_ to \relax:

\def\Three{T\_hree}
{\let\_\relax
\DTLfetch{data}{HeadA}{\Three}{HeadB}}% Drie

Other options include making \_ robust (via etoolbox with \robustify{\_}, say).

Werner
  • 603,163