使用 csname 定义实习命令(变量)及其设置器

使用 csname 定义实习命令(变量)及其设置器

我想定义一些宏来创建不同语言的文本;该命令是\newlang创建一个不可见的宏或变量来存储特定语言的文本和一个设置器来设置这个变量。

例如:\newlang{ar}将创建\@artxt来存储文本,并\setartext{text}设置\@artxt

当我想显示这些变量的内容时(假设我们调用了\newlang3 次),\csname只使用最后一个变量来显示其内容。这是代码:

\documentclass{article} 

\makeatletter

\newcommand\newlang[1]{ %
\ifdefined\@langs %
\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %
\else %
\def\@langs{#1} %
\fi
\@namedef{@#1txt}{}%
%
\expandafter\newcommand\csname set#1text\endcsname[1]{ %
%
\expandafter\def\csname @#1txt\endcsname{##1} %
} %
}

\newcommand{\@processTexts}[1]{ %
-----#1----\\
\ifcsname @#1txt\endcsname
  \csname @#1txt\endcsname
\else
  No #1 csname here
\fi\\
******\\
\@artxt \\
\@frtxt \\
}

\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}

\newcommand{\print}{ %
\ifdefined\@langs %
\@splitcomma{\@langs}%
\fi %
}

\makeatother


\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}

\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}
\print{}
Another text

 \end{document} 

它应该打印如下内容:

—–ar—-
arabic2
*****
arabic2
french
—–fr—-
french
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text

但是,它打印的是这个:

—–ar—-
No ar csname here
*****
arabic2
french
—–fr—-
No fr csname here
*****
arabic2
french
—–en—-
english
*****
arabic2
french
Another text

答案1

错误在于为每个条目向语言列表\@langs{}添加明确的标记,而留下的不是预期的,等等。{}ar{}ar

这样测试就必定失败,即由于未定义,\ifcsname ....它将返回错误分支。@ar{}text

\documentclass{article} 

\makeatletter

\newcommand\newlang[1]{%
  \ifdefined\@langs%
  \expandafter\def\expandafter\@langs\expandafter{\@langs,#1} %
  \else %
  \def\@langs{#1} %
  \fi
  \global\expandafter\newcommand\csname @#1txt\endcsname{foo}%
  \expandafter\newcommand\csname set#1text\endcsname[1]{ %
    % 
    \expandafter\gdef\csname @#1txt\endcsname{##1} %
  }%
}

\newcommand{\@processTexts}[1]{ %
  -----#1----\\
  \@ifundefined{@#1txt}{%
    No #1 csname here -- sorry%
  }{%
    \csname @#1txt\endcsname%
  }
  \\
  ******\\
}

\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}

\newcommand{\print}{ %
  \ifdefined\@langs %
  \@splitcomma{\@langs}%
  \fi %
}

\makeatother


\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}


\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}



\print{}
Another text

 \end{document} 

答案2

错误在这里:

\expandafter\def\expandafter\@langs\expandafter{\@langs{},#1} %

因为当你打电话的时候\@splitcomma,列表是

ar{},fr{},en

所以\tmp变得ar{}\csname @ar{}txt\endcsname非常不同\csname @artxt\endcsname

经过完善的版本,%行末有更正:

\documentclass{article} 

\makeatletter

\newcommand\newlang[1]{%
  \ifdefined\@langs
    \expandafter\def\expandafter\@langs\expandafter{\@langs,#1}%
  \else
    \def\@langs{#1}%
  \fi
  \@namedef{@#1txt}{}%
  \expandafter\newcommand\csname set#1text\endcsname[1]{%
    \expandafter\def\csname @#1txt\endcsname{##1}%
  }%
}

\newcommand{\@processTexts}[1]{%
  -----#1----\\
  \ifcsname @#1txt\endcsname
    \csname @#1txt\endcsname
  \else
    No #1 csname here%
  \fi
  \\
  ******\\
  \@artxt \\
  \@frtxt \\
}

\newcommand\@splitcomma[1]{\@for\tmp:=#1\do{\@processTexts{\tmp}}}

\newcommand{\print}{%
  \ifdefined\@langs
    \@splitcomma{\@langs}%
  \fi
}

\makeatother


\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}

\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}


\noindent\print{}
Another text

\end{document} 

在此处输入图片描述


使用不同的实现expl3

\documentclass{article} 
\usepackage{xparse}

\ExplSyntaxOn
% User level commands
\NewDocumentCommand{\newlang}{m}
 {
  \karim_lang_newlang:n { #1 }
 }

\DeclareExpandableDocumentCommand{\gettext}{m}
 {
  \karim_lang_gettext:n { #1 }
 }

\NewDocumentCommand{\print}{}
 {
  \karim_lang_print:
 }

% Variables
\seq_new:N \g_karim_lang_langs_seq
\prop_new:N \g_karim_lang_texts_prop

% Internal functions
\cs_new_protected:Nn \karim_lang_newlang:n
 {
  \seq_gput_right:Nn \g_karim_lang_langs_seq { #1 }
  \cs_new:cpn { set#1text } ##1
   {
    \prop_gput:Nnn \g_karim_lang_texts_prop { #1 } { ##1 }
   }
 }

\cs_new:Nn \karim_lang_gettext:n
 {
  \prop_if_in:NnTF \g_karim_lang_texts_prop { #1 }
   {
    \prop_item:Nn \g_karim_lang_texts_prop { #1 }
   }
   {
    No~text~for~#1~here
   }
 }

\cs_new_protected:Nn \karim_lang_print:
 {
  \seq_map_inline:Nn \g_karim_lang_langs_seq
   {
    \noindent
    ---##1---\\
    \karim_lang_gettext:n { ##1 } \\
    *****\par
   }
 }

\ExplSyntaxOff

\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}

\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}

\print

This is the text for French: \gettext{fr}

\end{document} 

在此处输入图片描述


宏的更简单版本:

\documentclass{article} 

\makeatletter

\let\karim@langs\@gobble
\newcommand\newlang[1]{%
  \expandafter\def\expandafter\karim@langs\expandafter{\karim@langs,#1}%
  \expandafter\newcommand\csname set#1text\endcsname[1]{%
    \@namedef{karim@#1@text}{##1}%
  }%
}

\newcommand{\gettext}[1]{%
  \ifcsname karim@#1@text\endcsname
    \@nameuse{karim@#1@text}%
  \else
    No text for #1!%
  \fi
}

\newcommand{\print}{%
  \ifx\karim@langs\@gobble
  \else
    \@for\next:=\karim@langs\do{%
      \noindent
      ---\next---\\
      \gettext{\next}\\
      ******\par
    }%
  \fi
}
\makeatother


\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}

\setartext{arabic}
\setfrtext{french}
\setentext{english}
\setartext{arabic2}


\print

\end{document} 

答案3

下面的代码看起来更简洁一些:

在此处输入图片描述

\documentclass{article} 

\usepackage{etoolbox}

\makeatletter

\newcommand{\@langs}{}
\newcommand\newlang[1]{%
  \xdef\@langs{\@langs,#1}%
  \@namedef{set#1text}##1{\@namedef{@#1txt}{##1}}%
}

\newcommand{\printlangs}{%
  \renewcommand{\do}[1]{%
    \if$##1$\else
      \par\noindent
      \begin{tabular}{c}
        \hline
        -- ##1 -- \\
        \hline
        \ifcsname @##1txt\endcsname
          \@nameuse{@##1txt}%
        \else
          No text specified%
        \fi
        \\
        \hline
      \end{tabular}
      \par\bigskip
    \fi
  }
  \expandafter\docsvlist\expandafter{\@langs}
}

\makeatother

\begin{document}
\newlang{ar}
\newlang{fr}
\newlang{en}

\setartext{arabic}
\setfrtext{french}
\setartext{arabic2}

\printlangs

Another text

\end{document}

语言存储在一个列表中,用于处理etoolbox(看如何迭代以逗号分隔的列表?更多细节)。

相关内容