csname を使用して内部コマンド(変数)とそのセッターを定義する

csname を使用して内部コマンド(変数)とそのセッターを定義する

さまざまな言語でテキストを作成するためのマクロをいくつか定義したいと思います。コマンドは、\newlang特定の言語のテキストを格納するための非表示のマクロまたは変数と、この変数を設定するためのセッターを作成します。

たとえば、テキストを保存するために\newlang{ar}を作成し、を設定します。\@artxt\setartext{text}\@artxt

これらの変数の内容を表示したい場合 ( \newlang3 回呼び出したと仮定)、\csname最後の 1 つだけを使用してその内容を表示します。コードは次のとおりです。

\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 ....テストは失敗します。つまり、が定義されていないため、false ブランチが返されます@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

となり\tmpar{}\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(見るカンマ区切りのリストを反復処理するにはどうすればいいですか?詳細については)。

関連情報