在 \href 中使用 \DTLfetch

在 \href 中使用 \DTLfetch

我正在尝试在 LaTeX 中创建一个新命令,该命令会创建一个 Google Map URL,指向与在调用的命令中指定为参数的地点相关的坐标(一种“表格查找”函数)。地点和相对坐标存储在一个coords.CSV文件中,必须使用datatool包读取。

Google 地图 URL 的结构应如下:

https://www.google.com/maps/?q=<LAT>,<LNG>

其中<LAT><LNG>是从文件加载的纬度和经度坐标coords.CSV,其结构如下:

Place,LAT,LNG
Test,42.0000,42.0000
...

该命令的定义方式如下:

\usepackage{datatool}
\newcommand{\coords}[1]{
    % Loads the CSV
    \DTLsetseparator{,}
    \DTLloaddb{coords}{doc/coords.csv}
        
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}}
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}}
    
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LNG ,\LNG}{#1}
}

最后,我这样使用新命令:

\coords{Test}

我已经设法正确加载命令中调用的地点的坐标(在本例中为“测试”),但是当我尝试生成 URL 时,LaTeX 给出了很多错误,其中大多数是! Undefined control sequence。如果我从生成 URL 的行(在命令定义内)中删除\LAT\LNG,我不会收到任何错误,但 URL 当然不包含任何坐标,因为它们存储在\LAT\LNG变量内。

有没有办法使用命令内定义的变量正确生成 URL \href

这是一个测试示例:

\documentclass[a4paper,10pt]{article}

\usepackage{hyperref}           
\usepackage{datatool}

\newcommand{\coords}[1]{
     % Loads the CSV
    \DTLsetseparator{,}
    \DTLloaddb{coords}{coords.csv}
        
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}}
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}}
    
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LAT ,\LNG}{#1}
}

\begin{document}

\coords{Test}

\end{document}

答案1

你可以使用与我的回答相同的技巧检索 `\DTLfetch` 的子字符串

\begin{filecontents*}{\jobname.csv}
Place,LAT,LNG
Test,42.0000,42.0000
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}
\usepackage{hyperref}

\DTLsetseparator{,}
\DTLloaddb{coords}{\jobname.csv}

\newcommand{\DTLfetchsave}[5]{% see https://tex.stackexchange.com/a/335489/4427
  \edtlgetrowforvalue{#2}{\dtlcolumnindex{#2}{#3}}{#4}%
  \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#2}{#5}}%
  \let#1\dtlcurrentvalue
}

\newcommand{\coords}[1]{%
  \DTLfetchsave{\LAT}{coords}{Place}{#1}{LAT}%
  \DTLfetchsave{\LNG}{coords}{Place}{#1}{LNG}%
  % Generates the URL pointing to Google Maps
  Place: \href{https://www.google.com/maps/?q=\LAT,\LNG}{#1}%
}

\begin{document}

\coords{Test}

\end{document}

我过去\jobname总是避免破坏我的文件。你可以为数据库使用任何你想要的文件名。

只需加载一次数据库,而不是每次调用时都加载\coords

答案2

我建议采取以下方法:

\documentclass[a4paper,10pt]{article}

% Let's create the file coords.csv - the directory ./doc  must exist 
% and writing-permission for that directory must be given!!!
% An already existing file won't be overwritten by the 
% filecontents*-environment (unless you provide the "overwrite"-option)
% and you will be informed about the fact that the file already
% exists via a message in the .log-file only. You won't get a 
% message on the terminal/console.
\begin{filecontents*}{doc/coords.csv}
Place,LAT,LNG
Test,42.0000,42.0000
\end{filecontents*}

\usepackage{hyperref}           
\usepackage{datatool}

\newcommand{\coords}[1]{%%%
    \begingroup
    % Load the CSV only if database "coords" doesn't already exist:
    \DTLifdbexists{coords}{}{%%%
      %\DTLsetseparator{,}% Comma is the default, so this probably is not needed.
      \DTLloaddb{coords}{doc/coords.csv}%%%
    }%%%
    % Assign the coordinates of the place whose name is denoted by the
    % parameter #1 to the macros \LAT and \LNG:
    \edtlgetrowforvalue{coords}{\dtlcolumnindex{coords}{Place}}{#1}%%%
    \dtlgetentryfromcurrentrow{\LAT}{\dtlcolumnindex{coords}{LAT}}%%%
    \dtlgetentryfromcurrentrow{\LNG}{\dtlcolumnindex{coords}{LNG}}%%%
    %%%
    % Use the name (denoted by #1) of the place as a hyperlink leading
    % to the corresponding URL of Google Maps:
    Place: \href{https://www.google.com/maps/?q=\LAT,\LNG}{#1}%%%
    \endgroup
}%%%

\begin{document}

\coords{Test}

\end{document}

我建议采用这种方法,因为您的代码存在一些问题:

问题 1:

您的\coords-command 产生了不需要的空格标记和\par-token:

我重写了它并添加了注释,指出了这些不需要的标记是从哪里产生的:

\newcommand{\coords}[1]{ %<- unwanted space-token yields horizontal space in horizontal mode
    % Loads the CSV
    \DTLsetseparator{,} %<- unwanted space-token yields horizontal space in horizontal mode
    \DTLloaddb{coords}{doc/coords.csv} %<- unwanted space-token yields horizontal space in horizontal mode
        %<- unwanted control word token \par
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}} %<- unwanted space-token yields horizontal space in horizontal mode
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}} %<- unwanted space-token yields horizontal space in horizontal mode
        %<- unwanted control word token \par                
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LAT ,\LNG}{#1} %<- unwanted space-token yields horizontal space in horizontal mode
}

问题 2:

hyperref-manual 指出 URL 参数中的标记\href必须完全可扩展。

您的命令\LAT\LNG不是完全可扩展的,因为它们的定义包含控制字标记\DTLfetch,而 datatool-package 的手册明确指出

\DTLfetch{students}{regnum}{\RegNum}{forename}
等于

\dtlgetrowforvalue{students}{\dtlcolumnindex{students}{regnum}}{\RegNum}%

\dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{students}{forename}}% \dtlcurrentvalue

这表明\DTLfetch(因此每个宏在某个阶段的扩展都会产生标记\DTLfetch)不能完全扩展,因为宏\dtlcurrentvalue是由定义的\dtlgetentryfromcurrentrow

问题 3:

我怀疑是否有必要在每次调用时加载数据库\coords

问题 4:

尽管这是默认设置,但您仍使用命令\DTLsetseparator将数据库条目的分隔符设置为逗号。因此,这可能已经过时了。

相关内容