マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

LaTeX 上で色々と実装してみる話(えるたそ編-1)

長かったナベアツ編はようやく終わった。さて次の課題であるが、「ナベアツ」の次といえば「えるたそ」が来る、というのは TeX 芸人の間では異論のないところであろう。そこで次の命令の実装を目標とする。

  • \FibEltaso{<正整数a>}{<正整数b>}{<正整数n>} : 最初の 2 項が a, b である一般フィボナッチ数列の第 n 項までの各項の整数について、その「えるたそ名」(1→「一反田えー」、2→「二反田びー」、…)を出力する。(各出力は段落で区切る。)ただし n は 2 以上とし、かつ a, b, n の値は「第 n 項までのどの項も高々十進 4 桁に収まる」範囲内で与えられるとする。

この課題は日本語の扱いのテストを兼ねている。ここでは原則として pLaTeX(+ jsarticle クラス)を用いることにする。テストでは、次の引数を与える。

\FibEltaso{8}{2}{13}

正常に動作したならば、次のような出力が得られるはずである。

なお、なんでフィボナッチなのかという疑問については右から左へ受け流すことにしよう。

TeX
(参照:アレアレ

なるべく奇をてらわない普通の実装、ということで。

\documentclass[a4paper]{jsarticle}
\makeatletter %!!!!!!!!!!!!!!!!!!!!!!!!! BEGIN TeX code
\newcount\xx@prv
\newcount\xx@cur
\newcount\xx@cnt
\newcount\xx@res
\def\xx@alpha@name#1{%
  \ifcase#1ぜっと\or
  えー\or びー\or しー\or でー\or いー\or えふ\or じー\or
  えいち\or あい\or じぇー\or けー\or える\or えむ\or えぬ\or
  おー\or ぴー\or きゅー\or あーる\or えす\or てぃー\or ゆー\or
  ぶい\or だぶりゅー\or えっくす\or わい\fi
}
\def\xx@kdigit#1{%
  \ifcase#1\or 一\or 二\or 三\or 四\or 五\or 六\or 七\or 八\or 九\fi
}
\def\xx@knumeral#1{%
  \expandafter\xx@knumeral@a\number#1/000\xx@nil
}
\def\xx@knumeral@a#1#2#3#4#5#6\xx@nil{%
  \xx@knumeral@b#1#2#3#4#5\xx@nil
}
\def\xx@knumeral@b#1/#2\xx@nil{%
  \xx@knumeral@c#2#1%
}
\def\xx@knumeral@c#1#2#3#4{%
  \xx@knum@pos#1{千}\xx@knum@pos#2{百}%
  \xx@knum@pos#3{十}\xx@kdigit{#4}%
}
\def\xx@knum@pos#1#2{%
  \ifnum#1>0 \ifnum#1>1 \xx@kdigit{#1}\fi #2\fi
}
\def\xx@eltaso@name#1{%
  \par\xx@knumeral{#1}反田%
  \xx@remainder{#1}{26}\xx@alpha@name{\xx@res}%
}
\def\xx@remainder#1#2{%
  \@tempcnta#1\relax \xx@res\@tempcnta \@tempcntb#2\relax
  \divide\@tempcnta\@tempcntb \multiply\@tempcnta-\@tempcntb
  \advance\xx@res\@tempcnta
}
\newcommand*\FibEltaso[3]{%
  \xx@prv=#1\relax \xx@cur=#2\relax \xx@cnt=#3\relax
  \xx@eltaso@name\xx@prv \xx@eltaso@name\xx@cur
  \advance\xx@cnt-2
  \@whilenum{\xx@cnt>\z@}\do{%
    \xx@res\xx@prv \xx@prv\xx@cur \advance\xx@cur\xx@res
    \xx@eltaso@name\xx@cur
    \advance\xx@cnt-1
  }%
  \par
}
\makeatother  %!!!!!!!!!!!!!!!!!!!!!!!!! END TeX code
\begin{document}
\FibEltaso{8}{2}{13}
\end{document}
expl3
(参照:アレ

欲張って(ナベアツの時と同様に)完全展開可能になるように実装しようとしたら物凄く大変なことになった。今のところの感触としては、「expl3 でも完全展開可能コーディングは難行である」といえそうだ。

\documentclass[a4paper]{jsarticle}
\usepackage{expl3}
\ExplSyntaxOn  %!!!!!!!!!!!!!!!!!!!!!!!! BEGIN expl3 code

\int_new:N \l__zrxx_ct_int
\cs_generate_variant:Nn \use:nn { nf }
\cs_generate_variant:Nn \use:nnn { fnf }
\cs_generate_variant:Nn \use:nnnn { ffff }
\cs_generate_variant:Nn \prop_get:Nn { Nf }

\cs_new_protected:Npn \newpar
  { \par }

\cs_new:Nn \__zrxx_list_assign:Nn
  {
    \int_zero:N \l__zrxx_ct_int
    \clist_map_inline:nn {#2}
      {
        \prop_put:NVn #1 \l__zrxx_ct_int {##1}
        \int_incr:N \l__zrxx_ct_int
      }
  }

\prop_new:N \l__zrxx_kdigit_prop
\__zrxx_list_assign:Nn \l__zrxx_kdigit_prop
  { {}, 一 , 二 , 三 , 四 , 五 , 六 , 七 , 八 , 九 }
\prop_new:N \l__zrxx_alpha_prop
\__zrxx_list_assign:Nn \l__zrxx_alpha_prop
  {
    ぜっと ,
    えー , びー , しー , でー , いー , えふ , じー ,
    えいち , あい , じぇー , けー , える , えむ , えぬ ,
    おー , ぴー , きゅー , あーる , えす , てぃー , ゆー ,
    ぶい , だぶりゅー , えっくす , わい
  }

\cs_new:Nn \zrxx_knumeral:n
  {
    \exp_args:Nf \__zrxx_knumeral_aux_i:n
      {
        \int_eval:n
          { \int_min:nn { 9999 } { \int_max:nn {#1} { 0 } } + 10000 }
      }
  }
\cs_new:Nn \__zrxx_knumeral_aux_i:n
  { \__zrxx_knumeral_aux_ii:nnnnn #1 }
\cs_new:Nn \__zrxx_knumeral_aux_ii:nnnnn
  { 
    \use:ffff
      { \__zrxx_knum_pos:nn {#2} { 千 } }
      { \__zrxx_knum_pos:nn {#3} { 百 } }
      { \__zrxx_knum_pos:nn {#4} { 十 } }
      { \prop_get:Nn \l__zrxx_kdigit_prop {#5} }
  }
\cs_new:Nn \__zrxx_knum_pos:nn
  {
    \int_compare:nNnT {#1} > { 0 }
      {
        \int_compare:nNnT {#1} > { 1 }
          { \prop_get:Nn \l__zrxx_kdigit_prop {#1} }
        #2
      }
  }

\cs_new:Npn \FibEltaso #1#2#3
  {
    \use:nf { \newpar }
      { \__zrxx_app_xfib:nnnN {#1} {#2} {#3} \__zrxx_one_eltaso:n }
  }

\cs_new:Nn \__zrxx_app_xfib:nnnN
  {
    \__zrxx_app_xfib_aux:ffffN {#1} {#2} { \int_eval:n { #3 - 1 } }
      { \__zrxx_one_eltaso:n {#1} } #4
  }
\cs_generate_variant:Nn \__zrxx_app_xfib:nnnN { fffN }
\cs_new:Nn \__zrxx_app_xfib_aux:nnnnN
  {
    \int_compare:nNnTF {#3} > { 0 }
      {
        \__zrxx_app_xfib_aux:ffffN {#2} { \int_eval:n { #1 + #2 } }
          { \int_eval:n { #3 - 1 } } { \use:nf {#4} { #5 {#2} } } #5
      }
      { #4 }
  }
\cs_generate_variant:Nn \__zrxx_app_xfib_aux:nnnnN { ffffN }

\cs_new:Nn \__zrxx_one_eltaso:n
  {
    \use:fnf { \zrxx_knumeral:n {#1} } { 反田 }
      { \prop_get:Nf \l__zrxx_alpha_prop { \int_mod:nn {#1} { 26 } } }
    \newpar
  }

\ExplSyntaxOff %!!!!!!!!!!!!!!!!!!!!!!!! END expl3 code
\begin{document}
\FibEltaso{8}{2}{13}
\end{document}

ここで、完全展開可能であることを確認するために文書中に

\edef\result{\FibEltaso{8}{2}{13}}\show\result

というコードを仕込んでおくと、次のような結果が端末に表示される。((\newpar\par を protected なマクロで包んだもの。\par の再定義時に \edef で展開されないための対策。))

> \result=macro:
->\newpar 八反田えいち\newpar 二反田びー\newpar 十反田じぇー\newpar 十二反田え
る\newpar 二十二反田ぶい\newpar 三十四反田えいち\newpar 五十六反田でー\newpar 
九十反田える\newpar 百四十六反田ぴー\newpar 二百三十六反田びー\newpar 三百八十
二反田あーる\newpar 六百十八反田てぃー\newpar 千反田える\newpar .

(なお、expl3 を pLaTeX で利用する場合、エンジンが e-pTeX である必要がある。)