命令扩展问题

命令扩展问题

请考虑以下 MWE:

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

\newcommand*{\convertlang}[1]{%
\ifstrequal{#1}{es}{spanish}{%
  \ifstrequal{#1}{lat}{latin}{%
    \ifstrequal{#1}{eng}{english}{%
      \ifstrequal{#1}{deu}{german}{%
        \ifstrequal{#1}{enm}{spanish}{% else
          % use English as foreign default
          english}}}}}}%

\newcommand*{\langtest}[1]{%
    \def\temp{\convertlang{#1}}%
    \ifstrequal{\temp}{spanish}{True}{False}%
}

\begin{document}

Testing: \convertlang{es} % yields: spanish

\langtest{es} % should yield: True

\end{document}

该命令\convertlang接受 ISO 8859 语言代码(eseng等)并将其转换为 babel 语言名称(spanishenglish等)。这很有效。

问题在于\langtest,它将字符串 ( ) 与使用spanish转换其参数的结果 ( ) 进行比较。#1\convertlang

\convertlang那里的and/or的扩展肯定有问题#1,但我不了解 TeX 宏扩展的基本原理。

我尝试这样做:

\newcommand*{\langtest}[1]{%
    \edef\temp{\convertlang{#1}}%
    \ifstrequal{\temp}{spanish}{True}{False}%
}

期望\temp得到其参数的扩展值。但这也行不通。

我怎样才能解决这个问题?

答案1

您可以使用可扩展和扩展字符串相等性测试(出于\pdfstrcmp可移植性的考虑,请参见\pdf@strcmppdftexcmdsLaTeX 中是否有类似“\ifnum”的“if”命令?)。该命令扩展了它的测试参数,并且本身也是可扩展的。(后者总是好的,前者则不然总是方便 [参见https://tex.stackexchange.com/q/230878/35864],但这正是我们想要的。)

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

\usepackage{pdftexcmds}

\makeatletter
\newcommand*{\IfStrEqualTF}[2]{%
  \ifnum\pdf@strcmp{#1}{#2}=\z@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\makeatother

\newcommand*{\convertlang}[1]{%
  \IfStrEqualTF{#1}{es}
    {spanish}
    {\IfStrEqualTF{#1}{lat}
       {latin}
       {\IfStrEqualTF{#1}{eng}
          {english}
          {\IfStrEqualTF{#1}{deu}
            {german}
            {\IfStrEqualTF{#1}{enm}
               {spanish}
               {english}}}}}}

\newcommand*{\langtest}[1]{%
  \IfStrEqualTF{\convertlang{#1}}{spanish}
    {True}
    {False}}

\begin{document}
Testing: \convertlang{es} % yields: spanish

\langtest{es} % should yield: True

\langtest{en} % should yield: False
\end{document}

测试:西班牙语//真//假


关于 MWE 的更多细节以及它为什么没有达到预期的效果。

第一的其中,etoolbox\ifstrequal定义是\newrobustcmd。因此它是健壮的,不可扩展的。这意味着

\edef\temp{\convertlang{#1}}

实际上并没有像我们希望的那样保存较长的语言名称\temp。它只是保存了一系列\ifstrequal测试。这意味着\temp不包含简单的字符串。

\edef\temp{\convertlang{es}}%
\show\temp

给出

> \temp=macro:
->\ifstrequal {es}{es}{spanish}{\ifstrequal {es}{lat}{latin}{\ifstrequal {es}{eng}{english}{\ifstrequal {es}{deu}{german}{\ifstrequal {es}{enm}{spanish}{english}}}}}.

您需要一个可扩展的字符串相等性测试,以允许\convertlang{#1}扩展到 中的语言名称\edef

\pdf@strcmp在这里很有用,因为它的字符串比较可扩展,这意味着通过此相等性测试定义的命令可以扩展为 中的比较结果\edef

第二问题是它\ifstrequal没有扩展其参数,因此即使\temp只包含一个字符串,测试也无法按预期工作

\def\temp{spanish}%
\ifstrequal{\temp}{spanish}{True}{False}%

仍然给出 'False',因为\temp 不是等于的字符串spanish,它扩展到等于的字符串spanish,这是一个微小但重要的差异。

有几种可能的方法可以解决这个问题。\temp这取决于你能保证什么,足以说

\expandafter\ifstrequal\expandafter{\temp}{spanish}{True}{False}%

或者

\ifdefstring{\temp}{spanish}{True}{False}%

如果您知道\temp在一个扩展步骤中将其扩展为字符串。如果需要更多步骤或想要完全扩展,则需要其他技巧。

\pdf@strcmp在这里很有帮助,因为它只是完全扩展了它的参数。这意味着只要\temp不包含在扩展上下文中爆炸的任何内容,就可以比较其“最终扩展字符串值”。您不必担心先对其进行扩展以进行测试。

答案2

expl3我会使用更简单的界面\str_case:nnF

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\convertlang}{m}
 {
  \nvaughan_convertlang:n { #1 }
 }

\cs_new:Nn \nvaughan_convertlang:n
 {
  \str_case:nnF { #1 }
   {
    {es}{spanish}
    {lat}{latin}
    {eng}{english}
    {deu}{german}
    {enm}{spanish}
   }
   {english}
 }

\NewExpandableDocumentCommand{\langtest}{m}
 {
  \str_if_eq:eeTF { \nvaughan_convertlang:n { #1 } } { spanish } { True } { False }
 }

\ExplSyntaxOff

\begin{document}

Testing: \convertlang{es} % yields: spanish

\langtest{es} should yield: True

\langtest{lat} should yield: False 

\end{document}

在此处输入图片描述

答案3

我不会使用长嵌套的 if 测试。这很难扩展。

\documentclass{article}

\ExplSyntaxOn
\tl_const:Nn \c__nvaughan_convert_es_tl{spanish}
\tl_const:Nn \c__nvaughan_convert_lat_tl{latin}
\tl_const:Nn \c__nvaughan_convert_eng_tl{english}
\tl_const:Nn \c__nvaughan_convert_deu_tl{german}
\tl_const:Nn \c__nvaughan_convert_enm_tl{spanish}

\newcommand*{\convertlang}[1]
 {
  \tl_if_exist:cTF {c__nvaughan_convert_#1_tl}
   { \tl_use:c {c__nvaughan_convert_#1_tl} }
   { english}
 } 

\newcommand*{\langtest}[1]{%
   \str_if_eq:eeTF {\convertlang{#1}}{spanish}
   {True}{False}}
\ExplSyntaxOff
\begin{document}

Testing: \convertlang{es} % yields: spanish
\convertlang{lat} \convertlang{blub}

\langtest{es} % should yield: True

\end{document}

在此处输入图片描述

相关内容