使用詞彙表 \ifglsused 嵌套在 \newglossaryentry 中

使用詞彙表 \ifglsused 嵌套在 \newglossaryentry 中

如果我想有條件地擴展基於或與另一個術語表術語相關的術語表條目,我發現條件\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沒有展開,因為namekey預設是不展開的。

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還沒有被使用,所以它的定義擴展為 的 false 部分(第三個參數)\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-α。

編輯:每次定義新條目時都會檢查擴充設置,但如果您有需要擴充欄位的條目,則只需再次開啟擴充功能。例如:

\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以不帶參數的控制序列開頭,則假定該控制序列是字元控制序列(例如\aeor )\o,並對其套用大小寫變更。例如, dos 的\makefirstuc{\ae foo}結果\MakeUppercase\ae foo是 Æfoo。這意味著

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

    \MakeUppercase\foo產生 FOO。

  4. 如果 的參數\makefirstuc以控制序列開頭,後面接著一個群組,則假定該控制序列是格式化指令。分組材料被假定為文本,並且大小寫變更將應用於該文本。例如,\makefirstuc{\textbf{foo}}相當於\textbf{\MakeUppercase foo}F哦。

不會對 的參數執行擴展,\makefirstuc因為這可能會導致具有單一參數的簡單文字區塊命令擴展為過於複雜而無法解析的內容。

返回 MWE,\Gls{TNFalpha}首次使用(或\Glsfirst{TNFalpha})嘗試時

\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已經以大寫字母開頭,因此無需擔心條件 in\ifnotused選擇第二個參數時的情況處理。

相關內容