使用 \newglossaryentry 中的词汇表 \ifglsused 嵌套条件词汇表术语

使用 \newglossaryentry 中的词汇表 \ifglsused 嵌套条件词汇表术语

如果我想有条件地扩展基于或与另一个词汇表术语相关的词汇表条目,我发现条件\ifglsused{}{}{}语句非常有用。

为了在父术语尚未使用的情况下满足父修改,我会\glsdisp{}{}确保先决条件被“使用”,但不会按照第一次使用时编程的方式显示。

\ifglsused{TNF}{\glsdisp{TNF}{\TNFalpha}}{\glsdisp{TNF}{tumor necrosis factor--\textalpha~(\TNFalpha)}}正如下面 MWE 中的项目 所示,这可以正常工作。

有趣的是,当它是子术语本身声明 \newglossaryentry{}中的 ie的一部分时,这个相同的评估会失败。first={}

梅威瑟:

\documentclass{article}
\usepackage[utf8]{inputenc}

\setlength\parindent{0pt}

%=========================================================================================================================================
% PACKAGES REQUIRED FOR GLOSSARIES
%=========================================================================================================================================

% Glossaries must be loaded before amsmath as per details in the following forum answer
% https://tex.stackexchange.com/questions/85696/what-causes-this-strange-interaction-between--and-amsmath
\usepackage[nogroupskip,toc,acronym]{glossaries} % must come after href   
\usepackage{scrwfile}%http://www.dickimaw-books.com/cgi-bin/faq.cgi?action=view&categorylabel=glossaries#glsnewwriteexceeded
\usepackage{siunitx,microtype,textcomp,textgreek}
\usepackage{etoolbox}
\makeglossaries

\newglossaryentry{TNF}{ 
    type={acronym}, 
    sort={tumor necrosis factor},  
    name={TNF}, 
    short={TNF}, 
    long={tumor necrosis factor}, 
    first={tumor necrosis factor (TNF)}, 
    description={tumor necrosis factor}     
}

\newcommand{\TNFalpha}{TNF--{\textalpha}}
\newglossaryentry{TNFalpha}{ 
    type={acronym}, 
    sort={tumor necrosis factor alpha},  
    name={TNF--{\textalpha}}, 
    short={TNF--{\textalpha}}, 
    long={tumor necrosis factor alpha}, 
    first={\ifglsused{TNF}{\glsdisp{TNF}{\TNFalpha}}{\glsdisp{TNF}{tumor necrosis factor--\textalpha~(\TNFalpha)}}}, 
    description={tumor necrosis factor alpha}
}

\begin{document}

    \begin{itemize}
        %\item \gls{TNFalpha}
        \item \gls{TNF}
        \item \gls{TNFalpha}
        \item \glsentryfirst{TNFalpha}
        \item \ifglsused{TNF}{\glsdisp{TNF}{\TNFalpha}}{\glsdisp{TNF}{tumor necrosis factor--\textalpha~(\TNFalpha)}}
    \end{itemize}

\end{document} 

更新:我通过创建一个新的词汇表键(指定基础)和新函数解决了这个问题,该函数独立于词汇表条目的创建执行相同的使用和显示逻辑。我基于此的函数模板如下: 在词汇表中创建新字段 newglossaryentry

因此,由于这个问题背后的原因 - 嵌套的词汇表扩展和最少的重复 - 是通过完全不同的方法解决的,我仍然有兴趣了解newglossaryentry

  • 我猜测,这意味着在实际调用它first={}之前,以某种方式进行评估\gls{},因此没有改变任何有用的布尔值,从而保证了永久的错误评估而不会失败,但如果知道的话就太好了。

  • 我的下一个猜测是,这与 \gls{} 的受保护状态有关,或者仅仅与代码的评估顺序有关?

答案1

这里有两个主要问题。

字段扩展

来自用户手册

当您定义新的词汇表条目时,默认执行扩展,但namedescriptiondescriptionpluralsymbol和 键除外(这些键都通过 抑制扩展)。symbolpluralsort\glssetnoexpandfield

(这些例外的原因是为了向后兼容以前将这些信息写入词汇表文件的早期版本。扩展抑制有助于在写入过程中保护脆弱的命令。)

为了实际操作,我们可以使用glossaries调试命令(仅在记录代码,不在用户手册中)。\showgloname将显示字段的定义name,将显示字段\showglofirst的定义,将显示字段的定义(每种情况下都需要一个参数,即条目标签)。(我已经精简了 MWE。)first\showglotexttext

\documentclass{article}

\usepackage{textgreek}
\usepackage[nogroupskip,toc,acronym]{glossaries}
\makeglossaries

\newglossaryentry{TNF}{ 
  type={acronym}, 
  sort={tumor necrosis factor},  
  name={TNF}, 
  first={tumor necrosis factor (TNF)}, 
  description={tumor necrosis factor}
}   

\newcommand{\TNFalpha}{TNF--{\textalpha}}
\newglossaryentry{TNFalpha}{
    type={acronym},
    sort={tumor necrosis factor alpha},
    name={\TNFalpha},
    first={tumor necrosis factor alpha~(\TNFalpha)},   
    description={tumor necrosis factor alpha}
}

\begin{document}
\showglofirst{TNF}
\showglofirst{TNFalpha}

\showgloname{TNF}
\showgloname{TNFalpha}

\showglotext{TNF}
\showglotext{TNFalpha}

\end{document}

这不会产生任何输出,但它会显示记录中的定义。(在 TeX 的交互模式下运行时,这些命令会中断运行,就像它们是错误消息一样。)以下是记录的相关部分。

first该条目的字段值TNF

> \glo@TNF@first=macro:
->tumor necrosis factor (TNF).

first该条目的字段值TNFalpha

> \glo@TNFalpha@first=macro:
->tumor necrosis factor alpha\protect \nobreakspace  {}(TNF--{\textalpha }).

因此这里的\TNFalpha命令已经扩展,不可破坏的空间也已扩展,~\textalpha由于受到保护所以不会扩展。

name该条目的字段值TNF

> \glo@TNF@name=macro:
->TNF.

name该条目的字段值TNFalpha

> \glo@TNFalpha@name=macro:
->\TNFalpha .

这里\TNFalpha没有展开,因为这个name键默认没有展开。

text键没有明确使用,因此它从字段中获取其值name,但在这种情况下会执行扩展。

text该条目的字段值TNF

> \glo@TNF@text=macro:
->TNF.

text该条目的字段值TNFalpha

> \glo@TNFalpha@text=macro:
->TNF--{\textalpha }.

name现场不同,\TNFalpha现已扩大。

因此,如果您在键\ifglsused内使用first,则默认情况下将对其进行评估当条目被定义时如果将上面的例子改为,则 的定义TNFalpha现在为:

\newglossaryentry{TNFalpha}{
    type={acronym},
    sort={tumor necrosis factor alpha},
    name={\TNFalpha}, 
    first={\ifglsused{TNF}{\TNFalpha}{tumor necrosis factor alpha~(\TNFalpha)}}, 
    description={tumor necrosis factor alpha}
}

然后\showglofirst{TNFalpha}仍然产生相同的结果:

> \glo@TNFalpha@first=macro:
->tumor necrosis factor alpha\protect \nobreakspace  {}(TNF--{\textalpha }).

这是因为当TNFalpha定义时,TNF尚未使用,因此其定义扩展为的错误部分(第三个参数)\ifglsused

嵌套链接

如果您\glsdisp向字段添加(或任何类似的命令)first,则最终会得到嵌套链接。\glsdisp\gls内部都使用相同的命令\@gls@link来处理超链接并将链接文本包装在 内\glstextformat。 因此嵌套这些命令可能会导致问题。

最简单的解决方案是关闭firstfirstplural字段的扩展,\glsdisp从字段值中删除,只使用来\glsunset标记TNF条目已被使用。像这样:

\documentclass{article}

\usepackage{textgreek}
\usepackage[nogroupskip,toc,acronym]{glossaries}
\makeglossaries

\newglossaryentry{TNF}{ 
  type={acronym}, 
  sort={tumor necrosis factor},  
  name={TNF}, 
  first={tumor necrosis factor (TNF)}, 
  description={tumor necrosis factor}
}   

\glssetnoexpandfield{first}
\glssetnoexpandfield{firstpl}

\newcommand{\TNFalpha}{TNF--{\textalpha}}
\newglossaryentry{TNFalpha}{
    type={acronym},
    sort={tumor necrosis factor alpha},
    name={\TNFalpha}, 
    first={\ifglsused{TNF}{\TNFalpha}{\glsunset{TNF}tumor necrosis factor alpha~(\TNFalpha)}},
    description={tumor necrosis factor alpha}
}

\begin{document}
\gls{TNFalpha}. \gls{TNF}.

\end{document} 

得出的结果为:

肿瘤坏死因子α(TNF-α)。

如果你把它们交换一下,你就有

\gls{TNF}. \gls{TNFalpha}.

代替

\gls{TNFalpha}. \gls{TNF}.

那么结果是

肿瘤坏死因子(TNF)。TNF-alpha。

编辑:每次定义新条目时都会检查扩展设置,但如果您有一个需要扩展字段的条目,则只需再次打开扩展即可。例如:

\newcommand{\stuff}{foo}
\newglossaryentry{stuff1}{name={\stuff},description={stuff1}}
\renewcommand{\stuff}{bar}
\newglossaryentry{stuff2}{name={\stuff},description={stuff2}}

这种定义在明确地这样做时看起来有点奇怪,但有时它是由内部使用 的命令完成的\newglossaryentry。在上面的例子中,\stuff当条目定义为 时需要扩展\stuff只是一个临时命令,其定义不断变化。如果没有这种情况,那么您可以将所有\glsetnoexpandfield命令放在开始定义任何条目之前。

大小写转换

首字母大写命令,例如\Gls使用\makefirstuc提供的mfirstuc。此命令确实尝试处理参数可能包含格式化命令的可能性,但由于没有通用的方法来确定命令的语法,特别是哪个参数是文本,哪个是标签,因此\makefirstuc必须应用一些限制才能正常工作。

  1. 如果参数以 开头\protect,则将其丢弃,并\makefirstuc应用于余数。例如,\makefirstuc{\protect\textbf{foo}}与 相同\makefirstuc{\textbf{foo}}
  2. 的参数\makefirstuc可以仅以文本开头。例如,\makefirstuc{foo}执行 执行\MakeUppercase foo结果为 Foo。而\makefirstuc{{fo}o}执行\MakeUppercase{fo}o执行结果为 FOo。
  3. 如果的参数\makefirstuc以没有参数的控制序列开头,则该控制序列将被视为字符控制序列(例如\ae或)\o,并将大小写更改应用于该序列。例如,\makefirstuc{\ae foo}执行\MakeUppercase\ae foowhich 会导致 Æfoo。这意味着

    \newcommand{\foo}{foo}\makefirstuc{\foo}
    

    执行\MakeUppercase\foo此操作会产生 FOO。

  4. 如果 的参数\makefirstuc以控制序列开头,后跟一个组,则控制序列被视为格式化命令。分组材料被视为文本,并将大小写更改应用于文本。例如,\makefirstuc{\textbf{foo}}相当于 ,\textbf{\MakeUppercase foo}其结果是F哦。

没有对 的参数进行扩展,\makefirstuc因为这可能导致具有单个参数的简单文本块命令扩展为过于复杂而无法解析的内容。

\Gls{TNFalpha}首次使用(或\Glsfirst{TNFalpha})尝试时返回 MWE

\makefirstuc{\ifglsused{TNF}{\TNFalpha}{\glsunset{TNF}tumor necrosis
factor alpha~(\TNFalpha)}}

这属于情况 4(控制序列后跟一个组)。因此,这试图做到

{\ifglsused{\MakeUppercase TNF}{\TNFalpha}{\glsunset{TNF}tumor necrosis 
factor alpha~(\TNFalpha)}}

这就是导致错误消息的原因。解决该问题的唯一方法是定义一个命令,其中第一个参数是需要更改大小写的文本。例如:

% \ifnotused{not used}{used}{label}
\newcommand*{\ifnotused}[3]{%
  \ifglsused{#3}{#2}{\glsunset{#3}#1}%
}

\newcommand{\TNFalpha}{TNF--{\textalpha}}
\newglossaryentry{TNFalpha}{
    type={acronym},
    sort={tumor necrosis factor alpha},
    name={\TNFalpha}, 
    first={\ifnotused{tumor necrosis factor alpha~(\TNFalpha)}{\TNFalpha}{TNF}},
    description={tumor necrosis factor alpha}
}

由于\TNFalpha已经以大写字母开头,因此无需担心处理条件\ifnotused选择第二个参数的情况。

相关内容