2012/11/10

LaTeXで "千反田える" してみた(5)

(前:LaTeXで "千反田える" してみた(4))

~付録A : わたし,気になります~

本記事は「LaTeXで "千反田える" してみた」シリーズの補足記事となります。
つまりは付録的な扱いです。

「LaTeXで "千反田える" してみた」シリーズは以下の通りです。
概略:LaTeXで "千反田える" してみた(1)
命令の解説:LaTeXで "千反田える" してみた(2)
動作の解説:LaTeXで "千反田える" してみた(3)
反省会:LaTeXで "千反田える" してみた(4)


○千反田えるって誰?
<古典部>シリーズの登場人物であり,TVアニメ「氷菓」のキャラクタです。
私は原作を読んだこともアニメを見たこともないので名前だけ知っているというレベルです。

○前にC言語でやって挫折したみたいだけど?
まずは何でそんなことをやったかの経緯を説明しましょう。

おそらくことの始まり
@artchanter氏「【本日の発見】「一反田えー、二反田びー、......二十六反田ぜっと、二十七反田えー、......」と定義した時、「千反田」は「える」になる。」
https://twitter.com/artchanter/status/262869992377307136

さて,ある日このようなツイートがされました。
このことを確認するためにプログラムを作って確認する人が出ました。

例:@_kabix氏「「【本日の発見】「一反田えー、二反田びー、......二十六反田ぜっと、二十七反田えー、......」と定義した時、「千反田」は「える」になる。」 というツイートが朝から回ってくるので本当にそうなるかプログラムを走らせた結果」
https://twitter.com/_Kabix/status/263229881435971584

「剰余を計算すればいいのに何でループ組んでるんだ」と言う人も見られたのですが
なぜかわざわざループを組んでやってみる人が続出しました。

かくいう私も,そのような流れに乗って,まずはC言語でやったわけなのです。
やった結果は変換結果が1つ後にずれたので,それをどう修正しようかと考えたところでやめました。
だって面倒くさくなったんですもの

○そして,今に至ると
そういうわけです。
ね,どうでもいい付録でしょう?

2012/11/07

LaTeXで "千反田える" してみた(4)

(前:LaTeXで "千反田える" してみた(3))

~一人反省会,あるいは大反省会~

1. あらすじ
できたので意気揚々とソースコードを公開したものの,動作に支障が出ないけどミスを発見した。
そういうわけで,あわててソースコードを修正,その後反省会へと移行したのであった。

2. 詳細
千反田えるマクロをつくってコンパイルした時「\ifcaseで用意された分岐が足りないんだけど」というエラーが出たので,とりあえず分岐を1個増やして対応(この時点でバグがあったことを放置してたわけだが)。
無事コンパイルできたし,所望の出力が得られたのでよしとした。

ところが,改めて眺めてみると,エラーの原因が各桁の数値を取り出す処理にあったことが判明
\@whilenum \@a > 10 \do{%
    \advance\@a by -10 \relax
さて,この処理のループ条件に問題があったわけだ。
ループ条件は "\@a > 10" つまりカウンタ\@aの値が10より大きいならループを続けるというもの。
今になって思えば,\@aが0~9のときにループを抜けてほしいのだが,\@a=10でもループを抜けるのである。
これがエラーの原因だったわけで,0~9までしか分岐を想定してないのに,
10を与えているから\ifcaseの分岐の数が足りないと言われたのである。
修正したら無意味な分岐は不要になったのでこれで一安心

3. なぜ正常?な動作をしていたか
\@a=0の処理が常時\@a=10の時に処理されたからである。
そういうわけで,\@a=0のときは何もしないという処理はずっと実行されないままだったのだ。

4. 終わりに
ソースコードは修正しました。
無着色,無添加なので(?)安心して使ってください。

(次:LaTeXで "千反田える" してみた(5))

○追記(2012/11/08)
どうやら私のようなひよっこが遊んでいたのを私よりもずっとハイレベルな方の目に留まってしまったようです(いわゆる "TeXnician" という人だと思います。決して "TeXpert" ではありません!)。
ブログ記事の題材として取り上げてもらい,どうしてこうなった!としか言えませぬ。
それでも TeX でプログラミングしたい人のための何か (2) - マクロツイーター

ちなみに,これの前の記事
それでも TeX でプログラミングしたい人のための何か (1) - マクロツイーター
では特に用心すべきこととして
  • TeX はフリーフォーマットじゃない
  • ローカル変数なんてものはない
  • 関数に相当するものは(普通は)ない
  • 引数パラメタ(#1 等)は実際に渡されたものの別名である
と書かれており,「これ(2個目以降)はきっと私のことだな」と思いながら,自分の書いた文を見返しております。
ソースにも "カウンタ(変数)" というあやしい表記をしており,理解を深めるべきであるとのお告げが聞こえます。

(氏がこのような記事を書いたのは,タイミングを考えると,私のようなひよっこが手を出したからではなかろうかと思っており,軽率であったと反省の意を示したく…)

LaTeXで "千反田える" してみた(1):概略 でも参考webページとして紹介したブログ記事の追記でも取り上げて頂きました。
プログラマーのためプログラミングLaTeX - プログラムモグモグ

あ,はい。よくもわるくも,全ての元凶はあなたの記事です(

○追記(2012/11/10)
時間を見つけて記事は随時修正していきます。
修正したら、こうして追記として最後に加えておきます。

LaTeXで "千反田える" してみた(3)

(前:LaTeXで "千反田える" してみた(2))

~とりあえず解説(動作編)~

LaTeXで千反田えるしてみたの記事も3個目になりました。

ソースコードを見たい人は
LaTeXで "千反田える" してみた(1)

使われている命令の大雑把な解説を見たい人は
LaTeXで "千反田える" してみた(2)
をそれぞれ見てください。

今回は千反田えるマクロの処理の流れについて実際に処理している順番通りに説明したいと思います。


1. \defでマクロ定義
そのまんまです。マクロを定義します。

2. \newcountで新しくカウンタを定義,数値の代入
カウンタとして\@a,\@loop,\@limitを定義しました。
\@aは数字を漢数字に直す部分と,それに対応するアルファベット(ひらがな)を出力する部分で使います。
\@loopはループ回数を数えるカウンタです。
\@limitはループ回数の終了条件用のカウンタです。
こいつには引数を代入した後,1を足します。
何でそんな事をするかと言うと,ループでの判定条件は \@loop < \@limit なので \@loop = \@limit になったらループから出ます。
つまりは1足しておかないと千反田が欲しくて1000を与えたけど,九百九十九反田で終わってしまうからです。

元々与える引数の数字を1大きくすればいいという話でもあります。

3. \@loop < \@limit を満たす間はループ
それだけです。このループの中に今回のマクロのキモがあります。

3-1. 各桁の値を取り出す。
まず,漢数字に変換するためには各桁の数字がいくつなのかを判定する必要があります。
残念ながら,TeX / LaTeXには剰余を求めると言うチート演算はないので割り算で取り出したい桁を1の位にする → それ以上の桁がなくなるまで10で引く
という処理をやっています。
前者は対応するやつで割ればいいだけです。1000とか100とか10とか。
後者の部分はマクロでいえば
\@a = \@loop \relax
\@whilenum \@a > 9 \do{%
    \advance\@a by -10 \relax
}
というところです。
剰余というのは言いかえれば割る数字より小さくなるまで減算するという処理です。
そのためひたすら10で引いてます。これが10の剰余にあたります。

さて,これで求めたい桁の数字が取り出せます。
そしたら次は対応する漢数字にしてやりましょう。

3-2. \ifcase で条件分岐(ループ回数(数字) -> 漢数字)
\ifcase でカウンタ\@aの値を判定しています。
\ifcase ならば,<\@a = 0> \or <\@a=1> \or ...
といった風に,0ならばこの処理,1ならばこの処理といった具合にカウンタの数値と処理の順番が対応しています。
これを利用して "カウンタが0ならば何もしない","カウンタが1~9ならば対応する漢数字をマクロ \@list に追加する" という処理にしています。
\@list はカウンタと同じように @ つきのものですが,マクロです。
こいつは \@list と書かれた部分があると,定義された処理で置換します。
つまりは,\@list には文字列を入れてあるので,そいつを表示するだけです。

3-3. \ifcase で条件分岐(ループ回数(数字) -> あるふぁべっと)
さて,今度はループ回数からあるふぁべっとに変換します。
Alphabetは26個しかないので当然,\ifcase で判定する数値も1~26の範囲で想定しましょう。
26個の分岐処理を作るのが面倒臭い?頑張ってください。
その気になれば,似たようなもので "ひらがなとカタカナの相互変換" マクロだって作れますよ。
(LaTeXで "千反田える" してみた(1) 参考webページ [3] 参照)

さて,ここでも各桁の数字を取り出すときと同じような処理をしています。
ループカウンタが "26より大きいならば" 26より小さくなるまで26で引き続けるという処理です。
ここが大事な処理でして,プログラミングで言うならば "26で剰余を取った後,演算結果に1を加える" に相当します。
この処理は各桁の数値を取り出す部分の10を26に変えればいいだけです。

3-4. 変換結果を表示する
さて,頑張ってループ回数からループで各桁の数字を取り出して漢数字に変換し,再びループ回数からループで今度はあるふぁべっとに変換し,ついに \@list の中身は "xxx反田 ..." になりました!
よくぞ頑張りました。あとはその変換結果を表示するだけです。
表示処理はこちら!
\@list
なんだかあっけないものですね。この一行だけで終わりです。
あとはループ回数のカウンタ \@loop に1を加えて再びループ判定に戻りましょう。

さて,マクロの流れの解説はこれで終わりです。
お疲れさまでした。

皆様もよきLaTeX Life をお送りください。

(次:LaTeXで "千反田える" してみた(4))

○追記(2012/11/10)
見出しを太字にし、リンクを追加しました。

2012/11/06

LaTeXで "千反田える" してみた(2)

(前:LaTeXで "千反田える" してみた(1))

~とりあえず解説(命令編)~

はい,解説(命令編)です。
マクロに使われている命令について大雑把に解説するだけの記事です。
正直TeX / LaTeXというものに対する理解は大したものではないので,大雑把にしか説明できません。
よくインターネットで検索すると見つかるくらいの情報しか書けないよ。
それでもいいならのんびりやっていくのでどうぞ。

ソースコードを追いながら解説はひどく面倒くさいので,使われている命令とその意味を書いておきます。
また,真面目にやろうとしたら面倒くさくなったため,「これを見ればなんとなくこんな動きをしていることが分かる」くらいのレベルのつもりです。

○@付のカウンタやマクロを使う
\makeatletter
\makeatother
こいつは@のついたカウンタやを使うための命令です。
通常,@のついたカウンタやマクロは本文のあるソースファイルで使わず,スタイルファイルやクラスファイル中に書いておくものなのですが,プリアンブルにマクロ定義を書きたかったりするときはこいつを前後に入れます。

(追記)
本文中でも使えますが,基本的にはプリアンブルかスタイルファイル,クラスファイルに入れておく方がいいでしょう。
そもそも,こういうマクロは分けておいた方がいいです。
プログラムを作るときにモジュールに分割することと同じようなものです。

○マクロを定義する(1)
\def
Example : \def\eltaso#1#2#3{処理}
\defは新しいマクロを作る命令です。
同じことをするコマンドに\newcommandがありますが,あれはLaTeXで用意されたものだったかな。
ただし,\defは同じ名前のマクロが存在しても無視して上書きするので,そこが気になる人は同じ名前のマクロがあるとエラーを出してくれる\newcommandを使いましょう。
使用例では引数を取るマクロを作ってますが,もちろん引数なしでもいけます。
ただし,取れる引数の数には上限があったはず(後で調べて追記します)。

(追記)
取れる引数の数は9が上限です。


○マクロの定義(2)
\edef
Example : \edef\@list{反田}
Example : \edef\@list{\@list える}  
\def命令と似たようなものですが,こいつの場合は\edefで定義したマクロは\edefを使わないと再定義できません。
途中で\def\@list{ちーちゃんかわいい}とか入れたって上書きされません。
ちなみに2個目の例では定義しようとしているマクロの中に同じ名前のものがありますが,これは再定義するときに使えて,既に定義されているものに新しく "える" という文字列をくっつけられます。
これを利用して,千反田えるマクロでは数字を頭につけています。


○新しいカウンタを定義する
\newcount
Example : \newcount\@a
新しいカウンタをつくる命令です。
例で示したように, \newcountの後にカウンタ名を書きます。
基本的に整数のみしか扱えません。
固定小数点を扱えるパッケージ(fp-package)もあるようです。

○カウンタに値を代入する
\@a = 1
\@a = \@loop
\@a = #1
カウンタに値を代入する操作?命令?です。
定数を代入できますし,別のカウンタの値も代入できます。
ここで,マクロの引数に与えたものだってもちろん代入できます。
その場合は#1,#2,#3といった感じになりますが,これは引数の順番です。

○カウンタの四則演算
\advance xxx by ...
\multiply xxx by ... 
\divide xxx by ... 
Example : \advance\@a by \@k
上から順番にカウンタ(xxx)に対してbyの後ろの値(...)を加算,乗算,除算する命令です。
byの後ろに来るものはカウンタでも定数でも引数でも構いません。
ただし,計算結果はカウンタ(xxx)に代入されます。

○ループ構文
\@whilenum
Example : \@whilenum \@loop < \@limit \do{処理}
LaTeXで用意されているループ構文の1つです。
\@whilenum と \do の間にある条件が満たされている間,カッコでくくられた処理を続けます。
比較には不等号と等号が使えます。
比較はカウンタ同士やカウンタと引数,変数と定数ができます。

○条件分岐
\ifcase
\ifcase\@a <0のとき> \or <1のとき> \or ...
Example : \ifcase\@a \edef\@list{零反田} \or \edef\@list{一反田} \or ...
これはカウンタの値を判定し,その数値によって出力を変えられますが,
一番最初の処理はカウンタの値が0のとき,その次は1のとき,と既に決まっております。
これを利用して1の時は一をくっつけ,2の時は二をくっつけ…とかやってます。

さて,これだけ書いておけばなんとなく分かるでしょう。

○最後に:\relaxって何?

なに?\relaxの説明がない?ああ,すまない。
すっかり忘れていた。
\relax
こいつを入れると精神的に穏やかになれます。
LaTeXで "千反田える" してみた(1) 参考webページ[1]参照)

(次:LaTeXで "千反田える" してみた(3))

○追記(2012/11/10)
変数と表記されていたところをカウンタやマクロに変えました。
また,使用している命令の分類ごとに見出しを付けました。
これで少しはより正確な表現に近付いたと思われます。
とはいっても,また正確にはほど遠いものだと思いますが。

LaTeXで "千反田える" してみた(1)

~概略~

1. すべての始まり
一体どういう流れで見つけたのかすらも忘れてしまったのですが,LaTeXで計算をやってしまおうというブログ記事を見つました[1]
最初,それを見た私はLaTeXで計算をやらせると言うよりはそのために使われてる命令が気になったので調べようと思いました。
ループ構文の方は苦戦しましたが[2]

んで,いろいろ調べていたらひらがなをカタカナに変換するというマクロを見つけました[3]

そこで私はひらめいたのです。
以前C言語でつくったけど挫折したあれ,できるんじゃないかと。

2. 必要な知識
LaTeXでマクロを作りました。
必要なコマンドの知識は次の通りです。
  • 自作マクロが定義できる
  • \newcount でカウンタが作れる
  • 作ったカウンタに数値の代入,四則演算ができる
  • \@whilenum でループが作れる
  • \ifcaseを使って条件分岐ができる
こんなことは既に知っている,という人はソースコードを見てみればいいと思います。
分からないから解説が欲しい,という人はこれから解説記事を書くので,そちらを見ればいいと思います。

3. 出来上がったもの
さて,私がつくって出来上がったソースコードが以下です。
\documentclass{jsarticle}
\makeatletter
% えるたそマクロ
\def\eltaso#1{%
% カウンタの定義
\newcount\@a % ループ回数からの算出用
\newcount\@loop % ループ回数カウント
\newcount\@limit % ループ回数上限(引数+1を代入)
% カウンタへの数値設定
\@loop = 1 \relax % 1を代入
\@limit = #1 \relax % 引数を代入
\advance\@limit by 1 \relax % 1を足す
% 引数の回数だけループ
\@whilenum \@loop<\@limit \do{%
    % マクロ定義({}内の文字を展開)
    \edef\@list{反田}
    % 各桁の数字を抽出
    \@a = \@loop \relax
    % 9より大きいなら10で引く
    % これを9より大きいという条件が満たされている間続ける
    \@whilenum \@a > 9 \do{%
        \advance\@a by -10 \relax
    }
    % \@aの数値で処理を分岐
    \ifcase\@a \or
        \edef\@list{一\@list} \or
        \edef\@list{二\@list} \or
        \edef\@list{三\@list} \or
        \edef\@list{四\@list} \or
        \edef\@list{五\@list} \or
        \edef\@list{六\@list} \or
        \edef\@list{七\@list} \or
        \edef\@list{八\@list} \or
        \edef\@list{九\@list}
    \fi
    \@a = \@loop \relax
    \divide\@a by 10 \relax
    \@whilenum \@a > 9 \do{%
        \advance\@a by -10 \relax
    }
    \ifcase\@a \or
        \edef\@list{十\@list} \or
        \edef\@list{二十\@list} \or
        \edef\@list{三十\@list} \or
        \edef\@list{四十\@list} \or
        \edef\@list{五十\@list} \or
        \edef\@list{六十\@list} \or
        \edef\@list{七十\@list} \or
        \edef\@list{八十\@list} \or
        \edef\@list{九十\@list}
    \fi
    \@a = \@loop \relax
    \divide\@a by 100 \relax
    \@whilenum \@a > 9 \do{%
        \advance\@a by -10 \relax
    }
    \ifcase\@a \or
        \edef\@list{百\@list} \or
        \edef\@list{二百\@list} \or
        \edef\@list{三百\@list} \or
        \edef\@list{四百\@list} \or
        \edef\@list{五百\@list} \or
        \edef\@list{六百\@list} \or
        \edef\@list{七百\@list} \or
        \edef\@list{八百\@list} \or
        \edef\@list{九百\@list}
    \fi
    \@a = \@loop \relax
    \divide\@a by 1000 \relax
    \ifcase\@a \or
        \edef\@list{千\@list} \or
        \edef\@list{二千\@list} \or
        \edef\@list{三千\@list} \or
        \edef\@list{四千\@list} \or
        \edef\@list{五千\@list} \or
        \edef\@list{六千\@list} \or
        \edef\@list{七千\@list} \or
        \edef\@list{八千\@list} \or
        \edef\@list{九千\@list}
    \fi
    \@a = \@loop \relax
    \@whilenum \@a > 26 \do{%
        \advance\@a by -26 \relax
    }
    \ifcase\@a \or
        \edef\@list{\@list えー } \or
        \edef\@list{\@list びー } \or
        \edef\@list{\@list しー } \or
        \edef\@list{\@list でー } \or
        \edef\@list{\@list いー } \or
        \edef\@list{\@list えふ } \or
        \edef\@list{\@list じー } \or
        \edef\@list{\@list えいち } \or
        \edef\@list{\@list あい } \or
        \edef\@list{\@list じぇー } \or
        \edef\@list{\@list けー } \or
        \edef\@list{\@list える } \or
        \edef\@list{\@list えむ } \or
        \edef\@list{\@list えぬ } \or
        \edef\@list{\@list おー } \or
        \edef\@list{\@list ぴー } \or
        \edef\@list{\@list きゅー } \or
        \edef\@list{\@list あーる } \or
        \edef\@list{\@list えす } \or
        \edef\@list{\@list てぃー } \or
        \edef\@list{\@list ゆー } \or
        \edef\@list{\@list ぶい } \or
        \edef\@list{\@list だぶりゅー} \or
        \edef\@list{\@list えっくす } \or
        \edef\@list{\@list わい } \or
        \edef\@list{\@list ぜっと }
    \fi
    \@list
    \advance\@loop by 1 \relax
    }
}
\makeatother
\begin{document}
\eltaso{1000}
\end{document}
こいつをコンパイルして得た結果(dviファイル)がこちらです。

25ページを費やしました。
二段組みにはしてないので,割ともったいない感じです。
一反田えー からはじまって 千反田える まで25ページです。

○参考にしたwebページ一覧
[1] プログラマーのためプログラミングLaTeX - プログラムモグモグ
http://d.hatena.ne.jp/itchyny/20121027/1351299600
これを見たのが始まり,かな。

[2] TeX のループ構文 - マクロツイーター
http://d.hatena.ne.jp/zrbabbler/20110828/1314537300
ループ構文で調べてみてみたものの,眺めた程度ですすいません

[3] メモ帳/TeXマクロ2 - MyTeXpert
http://mytexpert.sourceforge.jp/index.php?%A5%E1%A5%E2%C4%A2%2FTeX%A5%DE%A5%AF%A5%ED2
ここにあるひらがなをカタカナに変換するマクロを見て千反田えるしようと思いました。

(次:LaTeXで "千反田える" してみた(2))

○追記(2012/11/10)
大した修正はやっていませんが,文を少しと節見出しを○と太字にしました。
それと追記に書いていたソースコードを本文中に移動しました。

ところで,TeXの場合はソースコードと言う呼び方でいいんだろうか?