使用 csname 定義 intern 指令(變數)及其設定器

使用 csname 定義 intern 指令(變數)及其設定器

我想定義一些巨集來創建不同語言的文字;該命令會\newlang建立一個不可見的巨集或變數來儲存特定語言的文字以及一個設定器來設定該變數。

例如:\newlang{ar}將建立\@artxt儲存文本,並\setartext{text}設定\@artxt.

當我想顯示這些變數的內容時(假設我們呼叫了\newlang3次),使用\csnamejuste最後一個顯示其內容。這是代碼:

\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(看如何迭代逗號分隔的清單?更多細節)。

相關內容