我正在尝试在 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
将数据库条目的分隔符设置为逗号。因此,这可能已经过时了。