![宏不起作用:if-then-else 语句的意外行为](https://linux22.com/image/475444/%E5%AE%8F%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8%EF%BC%9Aif-then-else%20%E8%AF%AD%E5%8F%A5%E7%9A%84%E6%84%8F%E5%A4%96%E8%A1%8C%E4%B8%BA.png)
我在使用 LaTeX 宏创建词汇表时遇到了问题。其目的是为字母表中每个新字母生成部分,并为以相同字母开头的术语生成子部分。但是,宏只显示第一部分(例如,如果词汇表以 A 开头,则显示字母 A)。
% package
\usepackage{csvsimple}
\usepackage{xstring}
\usepackage{datatool}
% my macro
\newcommand{\createGlossary}[2]{
% Load data from CSV file using the specified separator
\DTLsetseparator{#1}
\DTLloaddb{glossary}{#2}
% Sort data alphabetically based on the term
\DTLsort{termine}{glossary}
% Variables to track the current and previous letters
\newcommand{\current}{}
\newcommand{\previous}{}
% Iterate over the data to create sections and subsections
\DTLforeach{glossary}{\term=termine,\description=descrizione}{%
% Extract the first letter of the term
\StrLeft{\term}{1}[\current]\par
\typeout{Current: \current}
\typeout{Previous: \previous}
\IfStrEq{\current}{\previous}{
\subsection*{\term}
\description
}{
\section*{\current}
\renewcommand{\previous}{\current}
}\par
}
}
尽管遵循与下面提供的 Python 代码类似的逻辑,并且逻辑正确运行,但 LaTeX 宏却失败了。
def print_names(name_list):
previous_initial = ''
for name in name_list:
if name[0] != previous_initial:
print(name[0])
previous_initial = name[0]
print(name)
names = ["Anna", "Giacomo", "Giovanni", "Luigi", "Marco", "Mario", "Paolo"]
print_names(names)
示例用法
\createGlossary{,}{glossary.csv}
将 glossary.csv 替换为包含词汇表数据的 CSV 文件的路径,并根据需要调整分隔符。
问题分析
问题似乎源于 \createGlossary 宏的行为就像“previous”和“current”变量始终相等,从而阻止创建字母表第一个字母以外的新部分。这实际上是我的调试输出:
Current: A
Previous:
Current: A
Previous: A
Current: A
Previous: A
Current: B
Previous: B
Current: B
Previous: B
Current: B
Previous: B
Current: B
Previous: B
Current: B
Previous: B
...
如果有人对如何调试和修复 \createGlossary 宏有任何见解或建议,我们将非常感谢您的帮助。
答案1
\renewcommand{\previous}{\current}
扩展标记后\previous
会产生标记\current
,因此的总扩展\previous
始终与的总扩展相同\current
,因此\IfStrEq
对于字符串相等的情况,-test 总是会产生分支。
而不是\renewcommand{\previous}{\current}
你需要做的\let\previous=\current
。
除此之外,
- 有一个环境
description
,其底层命令是\description
。为了不覆盖该命令,请在代码中定义的所有内部辅助宏的名称前加上“my”前缀。对于实际场景,建议使用更好的命名空间前缀。也许覆盖是/将被限制在由 打开的本地范围内\DTLforeach
,但此答案的初始版本的作者不确定是否是这种情况。 - 在标记化之后
{
,或者}
TeX 的读取装置处于状态 M(行的中间)。当读取装置处于状态 M 并遇到行的末尾时,该行的末尾通常/在正常情况下会在标记流中插入一个空格标记,如果 TeX 在处理时当前正在以水平模式排版内容,则这反过来可能会产生可见的水平空间。
因此,到处插入注释字符%%%
以避免出现不需要的空格标记。 \section*
并且\subsection*
通常在标题后开始一个新段落,因此插入标记\par
似乎已经过时了。
\newcommand\myprevious{}%
\newcommand\mycurrent{}%
\newcommand{\createGlossary}[2]{%%%
% Load data from CSV file using the specified separator
\DTLsetseparator{#1}%%%
\DTLloaddb{glossary}{#2}%%%
% Sort data alphabetically based on the term
\DTLsort{termine}{glossary}%%%
% Variables to track the current and previous letters
\gdef\mycurrent{}%%%
\gdef\myprevious{}%%%
% Iterate over the data to create sections and subsections
\DTLforeach{glossary}{\myterm=termine,\mydescription=descrizione}{%
% Extract the first letter of the term
\StrLeft{\myterm}{1}[\mycurrent]%%%
\typeout{Current: \mycurrent}%%%
\typeout{Previous: \myprevious}%%%
%\par
\IfStrEq{\mycurrent}{\myprevious}{}{%%%
\section*{\mycurrent}%%%
\global\let\myprevious=\mycurrent
}%%%
\subsection*{\myterm}%%%
\mydescription
%\par
}%%%
}%%%