列指定・整列・幅

\begin{tabular}{lcr}{lcr} は、LaTeX で 文章ではなくプログラムを書く 数少ない場所です。列の本数と揃え方だけでなく、各セルの前後に宣言を差し込む、列間の空きを別のものに置き換える、列のかたまりを繰り返す——といった指示をここに書けます。しかもこの 列指定 の語彙は、一つの設計から生まれたのではなく寄せ集めで育ちました。\newcolumntype はもともと David Carlisle の別パッケージ newarray.sty の機能で、array の説明書には「David が快く提供に同意してくれた」と書かれています。このページでは lcrp{幅} から出発し、m{幅}b{幅}>{…}<{…}@{…}!{…}*{n}{…}wW、そして幅をぴたりと合わせる tabularxX 列までを追います。

どの列指定にどのパッケージが要るか

素の LaTeX が持っているのは lcrp{幅}|@{…}*{n}{…} だけです。m{幅}b{幅}>{…}<{…}!{…}wW\newcolumntype は、すべて array パッケージ(TeX Live 2024 同梱は 2023 年 10 月 16 日版 v2.5g、Frank Mittelbach)が足すものです。X 列は tabularx(同 2023 年 7 月 8 日版 v2.11c、David Carlisle)で、tabularx 自身が array を必要とします。arraybooktabstabularx が内部で読み込むので、すでに有効なこともよくありますが、明示的に \usepackage{array} と書いておくのが安全です。

自分の文書でどちらが動いているかは、わざと存在しない列指定を書いてみる と一発で分かります。素の LaTeX なら ! LaTeX Error: Illegal character in array arg.array が入っていれば ! Package array Error: Illegal pream-token と、エラーの出どころが変わるからです。m{幅} を書いたのに「Illegal character」と言われたら、それは array を読み込み忘れているという意味です。

段落列の縦位置——p・m・b と、幅を固定する w・W

折り返す段落列は三種類あり、違いは セルの縦位置 だけです。array の説明書の表現をそのまま引けば、p{幅}\parbox[t]{幅} と等価で 上端揃えm{幅} は中身を 行の上下中央 に置き、b{幅}\parbox[b]{幅} と一致して 下端揃え になります。この違いが効いてくるのは、同じ行に背の高いセル(何行にも折り返した p 列や大きな画像)と一行きりのセルが混在するときです。既定の p だと隣の短いセルが行の上に張り付き、背の高いセルの中ほどと視線が合いません。m{幅} にすれば自然にそろいます。

幅は決めたいが折り返してほしくない、という要求には arrayw{揃え}{幅}W{揃え}{幅} があります。どちらも \makebox[幅][揃え]{セル} とほぼ同じ働きで、lcr のように振る舞いながら列の幅を固定します。二つの違いは事故の起こり方です——w中身が幅を超えても黙って隣にはみ出しW は同じ状況で overfull box の警告を出します。ただし W は溢れたとき必ず右へはみ出すので、揃え方が変わって見える点に注意してください。「幅を固定したいが、溢れたら気づきたい」なら W が正解です。

列指定縦位置・幅の決まり方折り返す?提供元
p{wd}上端揃え、\parbox[t]{wd} と等価する標準
m{wd}行の上下中央に置かれるするarray
b{wd}下端揃え、\parbox[b]{wd} と一致するarray
w{l}{wd}\makebox[wd][l] 相当。溢れても黙ってはみ出すしないarray
W{l}{wd}w と同じだが溢れると警告。溢れた分は右へしないarray
X幅を計算した p 列。表全体を目標幅に合わせるするtabularx

段落列を使ううえで覚えておきたい細かな既定が二つ。第一に、pmb の中では \parindent(段落の字下げ)が 0 になります。戻したければ >{\setlength{\parindent}{1em}}p{5cm} のように書きます。第二に、array\extrarowheight という長さも足します。正の値を与えると 各行の高さだけ が増え、深さは変わりません——\hline が大文字の頭に触れて見えるときの、いちばん素直な処方です(array の説明書自身、掲載している表に 1pt を設定したと明記しています)。

セルの前後に差し込む——>{…} と <{…}

array パッケージの目玉が >{宣言}<{宣言} です。>{宣言} はその列の 各セルの中身の直前に<{宣言}直後に 宣言 を挿入します。>{\bfseries}l と書けば、左揃えの列のセルすべてが、いちいち書かなくても太字になります。>{\itshape}c なら中央揃えの斜体、>{\color{red}}r なら右揃えの赤。段落列に対しては整列の宣言も書けて、>{\raggedright}p{4cm} は「折り返すが両端揃えにはしない」列を作ります。

ただし 重大な落とし穴 があります。\raggedright\raggedleft\centering の三つは内部で 行末の \\ を作り変えます。だからこれらを >{…} に入れた列が表の 最終列 にあると、\\ が行末として効かなくなり、次の行の & があふれて ! Extra alignment tab has been changed to \cr. になります。原因が列指定にあるのに、エラーは本文の行を指すので、初見ではまず気づけません。対策は宣言の 最後array\arraybackslash を添えること——>{\raggedright\arraybackslash}p{4cm} と書けば行末が復活します。最終列でなければ実害はありませんが、常に付ける習慣にしておくほうが安全です。

この \arraybackslash には出自の妙があります。もともとは tabularx が、まさにこの \raggedright との衝突を直すために導入した命令でした。いまは array.sty 本体が \def\arraybackslash{\let\\\tabularnewline} と定義しており、tabularx の側は「まだ定義されていなければ自分で定義する」という保険だけを残しています。つまり 道具が生まれた場所と、いま住んでいる場所が違う わけです。

latex
\usepackage{array}
% ...
% bold labels; a ragged-right wrapping column; a whole column in math mode
\begin{tabular}{ >{\bfseries}l >{\raggedright\arraybackslash}p{5cm} >{$}c<{$} }
  \hline
  Symbol & Meaning & \multicolumn{1}{c}{Value} \\
  \hline
  c & Speed of light in vacuum, a defining constant. & 2.998\times10^{8} \\
  g & Standard gravitational acceleration near the surface. & 9.807 \\
  \hline
\end{tabular}

三つめの列に使った >{$}c<{$} は、>< が最初に想定されていた用途そのものです。各セルの前後に $ が挟まれるので、その列のすべてのセルが インライン数式 として組まれ、数値や記号ばかりの列で毎回 $…$ を書かずに済みます。逆に array 環境(中身がもともと数式モード)で同じ書き方をすると、二つの $ が打ち消しあって その列だけ文章モード になります。なお見出し行だけは注意が必要で、Value をそのまま書くと数式として組まれて字間の抜けた斜体になってしまいます。上の例のように \multicolumn{1}{c}{Value} と書けば、そのセルだけ文章モードに戻せます。

>{…}<{…} に書けるのは 宣言(declaration) だけ、という制約も覚えておいてください。\bfseries\itshape のように後ろに引数を取らないものは問題ありませんが、引数を取る命令で終えてはいけません>{\textbf} は続くセルの中身を引数と思って読みかけ、エラーも出さずに何も太字にならないという、いちばん困る壊れ方をします。array の説明書も「>{\textbf} は列全体を太字にもしないし、最初の一文字を太字にもしない」と明記しています。太字にしたいなら宣言形の \bfseries です。

列の境目をいじる——@{…} と !{…}

列と列のあいだには、既定で \tabcolsep(片側 6pt、両側で 12pt)の空きが入ります。列指定のその位置に @{宣言} を置くと、array の説明書の言い方で「列間の空きを抑制し、代わりに decl. を挿入する」——つまり そこの空きが消え、代わりに書いたものが入ります。使いどころは二つ。第一に 表の外周の余白を削る こと。列指定の両端に @{}(空の宣言)を置けば、最初の列の左と最後の列の右の \tabcolsep が消え、表が本文の左端にぴたりとそろいます。booktabs を使う表でよく見る作法です。第二に 区切り文字を差し込む こと。数値を整数部と小数部の二列に割り、あいだに @{.} を置けば、ピリオドが固定位置に並んで小数点ぞろえになります。

@{…} と対になるのが !{宣言} です。縦罫 | を書ける場所に置け、| の代わりに任意の 宣言 を差し込みます。決定的な違いは !{…} が通常の列間の空きを消さない こと。array の説明書が挙げる例が分かりやすく、c!{\hspace{1cm}}c は列間が 既存の空きに 1cm を足した 幅になるのに対し、c@{\hspace{1cm}}cちょうど 1cm になります。「列のあいだに点線を引きたいが余白は保ちたい」といったとき(たとえば arydshln の点線命令を入れる)は !{…} が正解です。ちなみに array を読み込むと縦罫 | の扱いも変わり、罫線の太さのぶんだけ列間が 広がります——標準 LaTeX では罫線は既存の空きの中に置かれ、幅は変わりません。

列を繰り返し、名前を付ける——*{n}{…} と \newcolumntype

同じ並びの列が何本も続くときは *{回数}{列指定} で畳めます。array の説明書の定義では「列指定回数 回コピーしたもの」と等価。中央揃えが 6 本なら cccccc の代わりに *{6}{c} です。中身は複数の指定でもよく、*{3}{|c}||c|c|c| に展開されます。真価が出るのは >{…}@{…} を含む長い指定の繰り返しで、*{4}{>{$}c<{$}} と書けば数式モードの中央列が一挙に 4 本できます。

同じ組み合わせを文書のあちこちで使うなら、\newcolumntype{文字}{…} で名前を付けるほうが読みやすくなります。array の説明書自身が \newcolumntype{C}{>{$}c<{$}} を例に挙げており、以後は {C C C} と書くだけで済みます。\newcolumntype\newcommand と同じ形の任意引数も取れるので、幅を引数にした列型も作れます。定義が増えて混乱してきたら \showcols を書いてください——現在有効な \newcolumntype の一覧がログに出ます。

表を目標の幅に合わせる——tabularx の X 列

ここまでの列指定は、幅を こちらが決める ものでした。逆に「表全体を \textwidth にぴたりと合わせたい」場合に使うのが tabularxX です。\begin{tabularx}{\textwidth}{l X r} のように 目標の幅 を先に渡すと、X と書いた列の幅が計算で埋め合わされます。この列が特別なのは仕組みが単純なことで、説明書がはっきり書いているとおり X は幅が確定したあと p{計算値} に置き換えられます。実装でも既定は \newcommand{\tabularxcolumn}[1]{p{#1}} の一行。つまり X は「幅を後から埋める p 列」にすぎず、だからこそ >{\raggedright\arraybackslash}X のように p 列と同じ装飾がそのまま効きます。中身を縦中央にしたければ \renewcommand{\tabularxcolumn}[1]{m{#1}} と置き換えるだけです。

document.tex
\usepackage{tabularx}
% ...
% two X columns, the second twice as wide as the first
\begin{tabularx}{\textwidth}{@{}
    l
    >{\hsize=.667\hsize\linewidth=\hsize}X
    >{\hsize=1.333\hsize\linewidth=\hsize}X @{}}
  \hline
  Key & Short note & Longer note \\
  \hline
  alpha & fits in the narrow column & twice as wide, so prose wraps less often \\
  \hline
\end{tabularx}

X 列は既定ではすべて同じ幅になりますが、上のように >{\hsize=…\hsize\linewidth=\hsize}X を書けば 重みを変えられます。ただし説明書は二つの掟を課しています——X 列の幅の合計を変えないこと(上の例では 0.667 と 1.333 で合計 2、つまり X 二本ぶんのまま)、そして X 列をまたぐ \multicolumn を使わないこと。二つめは、幅の計算が \multicolumn の存在を前提にしていないためです。うまくいかない場合は \tracingtabularx を宣言すると、幅を探索する各回の値がログに出ます。

X 列に絡む代表的な症状も押さえておきましょう。X 以外の列の合計がすでに目標幅を超えていると、tabularx は負の幅を拒み、警告 Package tabularx Warning: X Columns too narrow (table too wide) を出して X 列を 1em 幅に落とします——結果として表は指定幅より広くなります。もう一つ、tabularx の本文は実際にはコマンドの引数として読まれ、幅を探して 表を何度も組み直す ため、\verb を書くと LaTeX Warning: \verb may be unreliable inside tabularx が出ます。tabularxtabularytabularray の比較や、そもそも紙に収まらない表の扱いは「広い表と幅の自動調整」で扱います。

いくつも組み合わせた例と、数値そろえの現代的な答え

最後に、ここまでの道具を一つの列指定に詰め込んだ例です。1 列目は太字の見出し列(>{\bfseries}l)、2 列目は左寄せで折り返す段落列(>{\raggedright\arraybackslash}p{5cm})、3・4 列目は数式モードの中央列を *{2}{…} でまとめて作り、外周の余白は両端の @{} で削っています。一行に複数の仕掛けを書けるのが列指定の強みですが、読みづらくもなるので、よく使う組み合わせには \newcolumntype で名前を付けるのが実務的です。

document.tex
\usepackage{array}
% ...
\begin{tabular}{@{} >{\bfseries}l >{\raggedright\arraybackslash}p{5cm} *{2}{c} @{}}
  \hline
  Symbol & Meaning & Value & Unit \\
  \hline
  $c$ & Speed of light in vacuum, a defining constant. & $2.998\times10^{8}$ & m/s \\
  $g$ & Standard gravity, an approximation near the surface. & $9.807$ & m/s$^2$ \\
  \hline
\end{tabular}

一つだけ、この列指定言語では やらないほうがよい ことも書いておきます。数値を小数点でそろえる目的なら、前に触れた @{.} ではなく siunitx パッケージの S を使ってください。S 列は数値を解析して整数部・小数点・小数部・指数・不確かさまで正しくそろえ、桁区切りや有効数字の体裁も整えます。ちなみに array の説明書は小数点そろえの自前のコード例を載せたうえで「このコードは出来が悪い」と自ら注意書きを付け、David Carlisle の dcolumn.sty にもっと良い版があると案内しています——パッケージの説明書が自分のサンプルをここまで正直に評するのは珍しいことです。