いきなりですが問題です.
以下のソースコードは,インデント(字下げ)がなく,非常に読みにくくなっています.
/* ordinal.c : 1st, 2nd, ... */ #include <stdio.h> int main(void) { int i; for (i = 1; i <= 1000; i++) { int mod100 = i % 100; int mod10 = i % 10; switch (mod100) { case 11: case 12: case 13: printf("%dth\n", i); break; default: switch (mod10) { case 1: printf("%dst\n", i); break; case 2: printf("%dnd\n", i); break; case 3: printf("%drd\n", i); break; default: printf("%dth\n", i); } } } return 0; }どんな方法でインデントしますか.
インデントしたソースファイルを作ること,ではなく,インデントする方法を複数,紹介するのが,本記事の主眼です.開発環境としては,Linuxを想定しています.geditとemacsが利用可能とします.
テキストエディタでファイルを開いて,1行1行,字下げを入れる(または入れない),というのは,愚直と分かっていても,真っ先に思い浮かぶ方法です.
そこで少しでも,手間を減すとしましょう.Emacsで上のファイルを(ordinal.cというファイル名であることを前提として),開いたあと,最初にインデントが必要な「int i;」のはじめの「i」にカーソルを置いてから,Tabキーを打てば,インデントしてくれます.
この,先頭でTabというやり方の嬉しいところは,入れ子が2重,3重にもなっていても,Tabキーだけで,適切な数だけ空白文字を挿入してくれることです.行頭にカーソルを移動させてからTabキーなのと,上から順に操作をしていく---途中ですると,「直前の行」に基づいてインデントされます---のを,忘れないようにしましょう.
ですが,Emacsが使えるのなら,編集中の中身すなわちバッファ全体をインデントしてくれる方法があります.まず,全体指定は,C-x h とします.Emacsになじみのない人向けに,きちんと書くと,Ctrlを押しながらXのキーを押し,すぐに両方を離します.それから,Hのキーを押します.この操作により,バッファ全体を領域指定するとともに,カーソルはバッファの先頭に移動します*1.
そのあと,C-M-\ です.ここも具体的に書くと,CtrlとAltを押しながら,円記号*2を押します.これで全体インデントが完了です.
ここからはEmacs以外の方法を,見ていきます.UbuntuやMintでよく使われるテキストエディタはgeditですが,これは上記のような便利なインデント機能を提供していません.
ただ,設定により少しだけ改善することができます.geditを起動したあと,メニューバーの「編集」,「設定」の順に選択します.「エディタ」タブの中に,「自動インデントを有効にする」というのがあって,その左をチェックしておくと,インデントの支援をしてくれるのです.
この設定を使って,Enter-Tab-Deleteの組み合わせで1行ごとにインデントができます.
上の(インデントしていない)プログラムで,「int i;」と,空行のあとの「for (i = 1; i <= 1000; i++) {」はインデント済みとし,次の「int mod100 = i % 100;」は,インデントがまだだとします.このとき,「{」の直後にカーソルを移動して,Enterキーを押すと,改行によって,「int mod100 = i % 100;」の直前に空行ができ,字下げはfor文と同じレベルになります.これが「自動インデント」の効果です.
そこでTabキーを押すと,1個分,字下げします.
そしてDeleteキーを押せば,「int mod100 = i % 100;」が,そのインデントになります.空行の改行文字が,デリートされたからです.
改行して,必要に応じてインデント位置を変えて,それから改行文字を削除,というのもまた,愚鈍な方法ですが,1行ごとにインデントが確認できるという点では便利です.なおgeditでは,Shiftを押しながらTabキーで,インデントのレベルを「上げる」こと,すなわち字下げを1個分,左にすることができます.
最後に,コマンドを使ってインデントする方法を,書いておきます.おすすめはastyleです.ただし,標準的なLinux環境では,インストールされていないかもしれません.UbuntuやMintなら(そして管理者権限を持っているなら),sudo apt-get install astyleでインストールできます.
実行するコマンドですが,カレントディレクトリにordinal.cがある状態で,astyle -A3 -s2 ordinal.cと実行します.そしてテキストエディタで,このファイルを開くと,中身は以下のようになります.
/* ordinal.c : 1st, 2nd, ... */ #include <stdio.h> int main(void) { int i; for (i = 1; i <= 1000; i++) { int mod100 = i % 100; int mod10 = i % 10; switch (mod100) { case 11: case 12: case 13: printf("%dth\n", i); break; default: switch (mod10) { case 1: printf("%dst\n", i); break; case 2: printf("%dnd\n", i); break; case 3: printf("%drd\n", i); break; default: printf("%dth\n", i); } } } return 0; }
このastyleコマンドは多彩なオプションを持ちます.詳細はhttp://astyle.sourceforge.net/astyle.htmlより見ることができます.
変換前のファイルは,元のファイル名に「.orig」をつけて(今回の例ならordinal.c.origという名前で)残っています*3.
コマンド実行により,ファイルが書き換わります.geditで,変換前のファイルを開いた状態で,端末上でastyleコマンドを実行してインデントを施し,geditに戻ると,オレンジ色のメッセージと,「再読み込み」「キャンセル」のいずれかを選択するボタンが表示されます.「再読み込み」を押せば,geditでも,同じインデント結果になり,編集も可能です.
インデントは,「普段から意識して行う」「テキストエディタの機能を活用する」の2つが心がけとしては大事です.
もう一つ,新規にファイルを作成する場合,書いてから,名前をつけて保存するのではなく,開いた直後の空の状態で,名前をつけて保存するのも,習慣にしましょう.そうすることで,拡張子(サフィックス)に応じた編集モードになり,シンタックスハイライティングのおかげで見やすく,編集しやすくなります.
コマンドでインデントを行うことについて,広く普及しているというわけではありませんが,英文を正しい綴りで書く際に,テキストエディタのスペルチェック機能を常時使用するのか,間違いを気にせず一気に書いてから,スペルチェッカにかけるのかという二者択一*4が,インデントにおいてもあっていいのではないかと,考えています.
今回使用したソースファイルは,基数(1, 2, 3, ...)に対応する序数(ordinal number; 1st, 2nd, 3rd, ...)を出力するもので,数に応じてst/nd/rd/thのいずれかの接尾辞を判断します.switch〜caseを組み合わせています.なお,switchブロック内の定数ラベルや「default:」について,インデントレベルが「switch」と同じなのは,EmacsのCモードや,astyleで今回使用したオプション(K&Rスタイル)の慣例です.
一昨年度まで担当していた1年後期の授業で,サンプルプログラムに使用してきました.今年度はリニューアルして,switch〜caseはif文に置き換えるとともに,「下2桁が11,12,13のいずれかのとき」を「十の位が1のとき」に変更*5したソースファイルを用意し,打ち込んでもらいました.
*1:カーソルの移動が望まないのなら,C-x 2でバッファを分割してから,全体指定,領域インデントを行い,C-x 0とすると,全体インデントをした上でカーソル位置はそのままとなります.
*3:元のファイルが不要な場合は,astyleコマンドに--suffix-noneまたは-nのオプションをつければよい,とのことですが,いったん残しておくことをおすすめします.なお,2度実施すると,元の「.orig」つきファイルが消去されます.
*4:ちなみに私が英文を書くときのスペルチェックは,Emacsのispell-regionと,Microsoft Wordとの二段構えで行っています.利用頻度は,8:2くらいです.
*5:この変更により,場合分けのパターンが少し変わるけれども,出力は変わらないことは,論理回路で活用される「カルノー図」を使って,視覚的に確かめることができます.