셀 병합

LaTeX에는 진정한 의미의 “셀 병합”이 없습니다. latex.ltx를 읽어 보면 가로 방향의 \multicolumn\multispan, 곧 TeX의 원시 명령 \omit에서 시작합니다. \omit은 “이 셀의 열 템플릿을 버린다”는 명령입니다. 이웃과 붙이는 것이 아니라, 정해진 틀을 무시하고 스스로 폭을 차지할 뿐입니다. 세로 방향의 \multirow 는 더 대담해서, 아래 행까지 늘어질 만큼 큰 상자에 글자를 놓을 뿐입니다. 이 두 구현이 ! Misplaced \omit. 오류부터 아래 행에 글자가 겹치는 사고까지, 이 페이지에서 다루는 대부분의 걸림돌을 설명해 줍니다. 아울러 정말 까다로운 부분, 즉 병합한 셀 아래에 \cline\cmidrule로 선을 긋는 문제도 살펴봅니다.

가로 방향 병합 — \multicolumn, 그리고 셀 맨 앞에서만 쓸 수 있는 이유

형식은 세 인수의 \multicolumn{n}{spec}{text} 입니다. n은 가로지를 열의 수, spec만들어진 하나의 셀 에 대한 열 지정, text가 내용입니다. 표준 LaTeX에 내장되어 있어 패키지가 필요 없습니다. 핵심은 spec병합 후의 한 열 에 대한 지정이며 원래 n개 열의 지정을 이어받지 않는다는 점입니다. 그래서 l, c, r 중 하나만 반드시 씁니다. 둘을 쓴 \multicolumn{2}{cc}{…}! Missing \endgroup inserted.! Extra alignment tab has been changed to \cr. 를 연달아 내며 망가집니다. 반대로 spec에는 세로줄 |이나 @{…}도 쓸 수 있어, 이 병합 셀에 대해서만 선과 열 사이 공간을 덮어쓸 수 있습니다.

\multicolumn셀의 맨 처음에 놓여야 합니다. X \multicolumn{1}{c}{Y} & Z처럼 무언가를 쓴 뒤에 부르면 ! Misplaced \omit. 가 납니다. 앞서 말했듯 \multicolumn의 실체는 \omit이고, 이는 “이 셀의 템플릿을 쓰지 않는다”고 선언하는 원시 명령입니다. 그런 선언은 셀이 시작되기 전에만 의미를 가집니다. 오류 메시지가 \multicolumn이 아니라 \omit의 이름으로 오는 것은 그 때문입니다.

latex
\begin{tabular}{lcc}
  \hline
  \multicolumn{3}{c}{Sales summary} \\
  \hline
  Item & H1 & H2 \\
  \hline
  Domestic & 120 & 145 \\
  Overseas & 80  & 96  \\
  \hline
\end{tabular}

첫 행은 원래 3열로 나뉘어야 할 행을 \multicolumn{3}{c}{Sales summary}로 하나의 가운데 정렬 셀로 합쳐 표 전체의 제목으로 삼습니다. 병합된 행에서도 그 행의 셀 합계는 반드시 선언한 열 수와 일치 해야 하지만, 여기서는 \multicolumn{3}{…}가 세 열을 모두 맡으므로 &가 필요 없습니다. 또 하나 기억할 것은 n1로 두는 사용법입니다. 열을 가로지르지는 않지만 그 셀만 정렬을 덮어쓰거나 그 위치의 세로줄 |을 없앨 수 있습니다. 숫자 열(r)의 머리글만 가운데에 두고 싶다면 \multicolumn{1}{c}{Header}라고 쓰고, 외곽선 있는 표에서 한 칸만 세로줄을 빼고 싶다면 spec|를 쓰지 않으면 됩니다.

외곽선 있는 표에서 \multicolumn 두 개를 나란히 둘 때는 세로줄을 한쪽에만 쓰세요. \multicolumn{2}{|c|}{left} 뒤에 \multicolumn{2}{|c|}{right}를 이어 쓰면 경계에 선이 두 겹으로 그려져 그 한 줄만 눈에 띄게 굵어 보입니다. \arrayrulewidth를 키우면 한눈에 드러납니다. 올바른 형태는 뒤쪽에서 앞의 막대를 빼는 것입니다. \multicolumn{2}{c|}{right} 입니다. 이는 소박한 구현의 부작용으로, \multicolumn은 버린 템플릿 대신 쓴 것만 그대로 그릴 뿐 중복까지 정리해 주지는 않습니다.

세로 방향 병합 — multirow 패키지와 \multirow의 인수

세로로 여러 행을 가로지르는 셀은 표준 명령으로 만들 수 없으므로 multirow 패키지 를 불러옵니다(TeX Live 2024에는 2021년 3월 15일자 v2.8). 잊으면 그저 ! Undefined control sequence. 가 납니다. 완전한 형식은 여섯 자리, 곧 \multirow[vpos]{nrows}[bigstruts]{width}[vmove]{text} 이며 필수는 nrows, width, text 셋뿐입니다. 가로지를 행 수, 셀의 폭, 그리고 내용입니다. 폭에 * 를 넘기면 내용의 자연 너비로 조판되므로 \multirow{3}{*}{Label}이 가장 단순한 형태가 됩니다.

결정적으로 중요한 규칙은 가로질러지는 아래 행의 셀을 비워 두는 것 입니다. \multirow는 위쪽 행에 놓고, 이어지는 행에서는 그 열 자리를 &만으로 넘깁니다. 공식 문서의 표현으로는, 그 열의 다른 행을 비워 두어야 하며 “그러지 않으면 \multirow가 만든 것이 그것을 덮어쓴다”고 합니다. 실제로 내용을 쓰면 오류는 전혀 나지 않고 두 글자가 같은 자리에 겹쳐 인쇄될 뿐입니다. nrows음수도 가능 합니다. 양수면 “이 행과 아래 n−1행”, 음수면 “이 행과 위 |n|−1행”으로 가로지르는 행 수는 같습니다. 명령을 맨 위 행에 쓰느냐 맨 아래 행에 쓰느냐의 차이 일 뿐입니다. 소수도 쓸 수 있어 \multirow{2.5}{*}{…}처럼 높이를 미세 조정할 수도 있습니다.

document.tex
\usepackage{multirow}
% ...
\begin{tabular}{|l|l|c|}
  \hline
  \multirow{2}{*}{Fruit}     & Apple  & 380 \\
                             & Orange & 120 \\
  \hline
  \multirow{2}{*}{Vegetable} & Carrot & 90  \\
                             & Radish & 150 \\
  \hline
\end{tabular}
인수역할비고
[vpos]세로 정렬(선택, 맨 앞)기본은 c, t / b도 가능
nrows가로지를 행 수(필수)양수는 아래로, 음수는 위로. 소수도 가능
[bigstruts]가로지르는 범위의 bigstrut 총수(선택)기본 0. t / b / tb를 앞에 붙여 세밀 제어
width셀 폭(필수)*는 자연 너비, =는 열의 폭, 절댓값은 parbox
[vmove]위치 미세 조정(선택, text 앞)양수는 위로, 음수는 아래로
\multirowsetuptext 직전에 전개되는 설정초깃값은 \raggedright. renewcommand로 변경

width* 대신 절댓값을 주면(\multirow{2}{4em}{…}) 내용이 그 폭의 parbox 로 조판되어 긴 레이블이 줄바꿈됩니다. 이 형태로 쓰면 \multirow의 글자가 양쪽 정렬이 아니라 왼쪽 정렬로 보인다 는 것을 알아차릴 수 있습니다. 버그가 아니라 사양으로, text 직전에 전개되는 훅 \multirowsetup의 초깃값이 \raggedright이기 때문입니다. 가운데로 맞추고 싶다면 \renewcommand{\multirowsetup}{\centering}으로 바꿔 씁니다. 또 하나, width에는 = 도 넘길 수 있는데 “지금 들어 있는 열에 정의된 폭을 쓴다”는 뜻입니다. p{} 열이나 tabularxX 열 안에서 편리하지만, 폭이 정해지지 않은 열에서 쓰면 이상하게 넓은 결과가 나옵니다.

\multirow는 자리를 비워 주지 않습니다 — 글자가 아래 행으로 넘칠 때

이것이 \multirow의 가장 유명한 사고입니다. \multirow는 자기가 필요로 하는 세로 공간을 표가 확보하게 만들지 않습니다. 상자의 높이는 nrowsbigstruts에서 추정 될 뿐이며, 실제 행의 높이를 모르기 때문입니다. 그래서 내용이 키 큰 상자가 되면 아래 행이나 표 바깥으로 그대로 넘쳐 나갑니다. 공식 문서도 약물 부작용 목록 표를 예로 들어, 두 \multirow 항목이 “너무 높아서 첫 번째는 두 번째 항목을 파고들고 두 번째는 표 밖으로 삐져나온다”고 솔직하게 적고 있습니다. 내용의 분량에 비해 nrows가 너무 작을 때 이 증상이 나타납니다.

고치는 방법은 셋이며, 앞의 둘은 공식 문서가 제시합니다. 첫째, 빈 행을 더해 겹침을 덮는 것 입니다. 모자란 만큼 & & \\를 써 넣습니다. 가장 확실한 길이고 행 수만 세면 됩니다. 둘째, 행 자체를 세로로 늘리는 것 입니다. 폭이 0인 버팀목, 예컨대 \newcommand{\mystrut}{\rule[-8pt]{0pt}{20pt}}를 각 행에 두어 높이를 법니다. (대신 bigstrut 패키지의 \bigstrut을 쓰고 그 개수를 [bigstruts]에 신고하는 방법도 있습니다.) 셋째, nrows를 실제보다 크게, 필요하면 소수로 신고하는 것 입니다. 가장 간편하지만 선과의 관계가 쉽게 어긋나므로 마지막 수단으로 남겨 둡니다.

document.tex
\usepackage{multirow}
% ...
% the label wraps to four lines but the block has only two rows,
% so raise nrows to 4 and add two empty rows to cover the overlap
\begin{tabular}{|l|c|}
  \hline
  \multirow{4}{4em}{A long label that wraps} & one \\
                                             & two \\
                                             &     \\
                                             &     \\
  \hline
  next & row \\
  \hline
\end{tabular}

“행의 높이를 모른다”는 같은 약점은 표 어딘가에 유난히 키 큰 행이 있을 때 도 드러납니다. 문서의 예는 셋째 행만 p{4cm} 열에서 길게 접히는 표인데, 그 결과 \multirow{3}*{Week 38}이 블록의 시각적 중심보다 위로 밀립니다. 행 높이가 고르지 않으면 \multirow가 추정한 중심과 눈으로 보는 중심이 어긋나는 것입니다. 이런 어긋남은 [vmove]에 작은 길이를 주어 손으로 고칩니다. .1ex 같은 상대 단위를 쓰면 나중에 본문 글자 크기를 바꿔도 보정값이 대체로 살아남습니다. 이 역시 공식 문서의 조언입니다.

병합 셀에 선이 닿을 때 — \hline이 아니라 \cline과 \cmidrule

이 주제에서 가장 까다로운 대목입니다. \multirow가 가로지르는 행 사이에 \hline을 쓰면 선이 병합 셀의 글자를 가로질러 그어집니다. 레이블이 취소선을 그은 것처럼 보이는데, \hline은 두 행 사이에 표 전체 폭의 \hrule을 깔 뿐 그 위에 무엇이 얹혀 있는지 모르기 때문입니다. \arrayrulewidth를 굵게 하면 글자가 선에 꿰뚫린 모습이 뚜렷이 보입니다. 대책은 단순합니다. 그 열을 선에서 빼는 것 입니다. 열 범위를 지정해 표준 LaTeX에서는 \cline{2-3}, booktabs를 쓴다면 \cmidrule{2-3}을 씁니다.

document.tex
\usepackage{multirow}
% ...
% \hline here would draw straight through the word "Group";
% \cline{2-3} spares column 1
\begin{tabular}{|l|l|c|}
  \hline
  \multirow{2}{*}{Group} & alpha & 1 \\
  \cline{2-3}
                         & beta  & 2 \\
  \hline
\end{tabular}

\cline\cmidrule은 범위를 지정할 수 있다는 점에서는 같지만 성격이 다릅니다. \cline{i-j}는 굵기가 \arrayrulewidth(기본 0.4pt)이고 지정한 열의 끝에서 끝까지 정확히 뻗으므로, 이웃한 두 \cline은 이어져 한 줄로 보입니다. booktabs\cmidrule{i-j}는 더 가늘어 굵기가 \cmidrulewidth(기본 0.03em, 본문 10pt에서 약 0.3pt)이고, 위아래로 \aboverulesep\belowrulesep의 여백을 둡니다. 실무에서 더 중요한 것은 소괄호 선택 인수로 양끝을 다듬을 수 있다는 점입니다. \cmidrule(lr){2-3}이라고 쓰면 좌우가 조금 짧아져 이웃한 \cmidrule과 사이에 틈이 생기고 서로 다른 선으로 읽힙니다. 머리글 그룹을 여럿 나란히 둘 때의 정석입니다.

latex
\usepackage{booktabs}
% ...
% two \multicolumn headers, each underlined by its own trimmed rule
\begin{tabular}{lcccc}
  \toprule
       & \multicolumn{2}{c}{2024} & \multicolumn{2}{c}{2025} \\
  \cmidrule(lr){2-3} \cmidrule(lr){4-5}
  Item & Q1 & Q2 & Q1 & Q2 \\
  \midrule
  Apple & 1 & 2 & 3 & 4 \\
  \bottomrule
\end{tabular}

이것이 \multicolumn과 선을 조합한 실무의 정석 형태입니다. \multicolumn{2}{c}{2024}가 두 열에 걸친 머리글을 만들고, 바로 아래의 \cmidrule(lr){2-3}이 “이 두 열은 한 묶음”이라고 알려 줍니다. (lr)을 빼면 두 선이 이어져 그룹의 경계가 보이지 않게 됩니다. 또 두 개의 \cmidrule같은 열 범위에 겹쳐 긋고 싶다면 booktabs\morecmidrules를 사이에 넣습니다. 그냥 둘을 이어 쓰면 같은 선 줄에 속한 것으로 다루기 때문입니다. 색을 넣은 표에서는 \cline이 배경색에 덮여 보이지 않을 수 있는데, 그 증상과 hhline을 쓰는 우회책은 “표에 색 입히기” 페이지에서 다룹니다.

블록 병합 — \multirow는 \multicolumn 안쪽에

가로와 세로를 모두 가로지르는 직사각형 블록\multirow\multicolumn의 조합으로 만듭니다. 순서는 정해져 있으며 \multirow\multicolumn 안쪽에 두는 것 이 맞습니다. 공식 문서도 \multicolumn{2}{c}{\multirow{3}{*}{Multi-multi}}를 예로 들고, 반대로 중첩하면 “will not work”라고 명시합니다. 바깥쪽 \multicolumn이 가로를, 안쪽 \multirow가 세로를 맡는다고 기억하세요. 그리고 \multirow의 철칙은 여기서도 유효합니다. 아래 행의 같은 자리는 \multicolumn의 형태를 유지한 채 내용만 비웁니다.

document.tex
\usepackage{multirow}
% ...
\begin{tabular}{|l|l|c|}
  \hline
  \multicolumn{2}{|c|}{\multirow{2}{*}{Region and class}} & Count \\
  \multicolumn{2}{|c|}{}                                  &       \\
  \hline
  East & Kanto  & 12 \\
  \cline{1-3}
  West & Kansai & 9  \\
  \hline
\end{tabular}

한 칸 안에서 줄만 나누는 것은 병합이 아닙니다 — makecell

여기서 하나 구분해 둡시다. “한 칸 안에서 줄을 나누고 싶다”는 것은 셀 병합이 아닙니다. l, c, r 열은 줄바꿈하지 않으므로 셀 안에 \\를 직접 쓰고 싶어지지만, 그렇게 하면 오류 없이 표가 조용히 무너집니다. A & B\\C \\라고 쓰면 TeX는 \\를 행 끝으로 읽고 C를 다음 행의 첫 셀로 조판합니다. 오류가 나지 않는 만큼 이쪽이 더 성가십니다. 짧은 문자열을 원하는 위치에서 줄바꿈하고 싶을 뿐이라면 makecell 패키지\makecell{…} 이 가장 간단합니다.

\makecell{line1\\line2}는 내용을 작은 한 열짜리 tabular 로 조판하며, 그렇기 때문에 그 안에서 \\를 강제 줄바꿈으로 쓸 수 있습니다. 선택 인수로 정렬도 지정할 수 있어 \makecell[l]{…}(왼쪽), \makecell[t]{…}(위쪽)처럼 세로와 가로 정렬을 한 글자씩 넘깁니다(기본은 둘 다 가운데). 머리글용으로는 공통 글꼴과 여백이 설정된 \thead{…} 도 있습니다. 내용이 길고 폭에 맞춰 자동으로 줄바꿈되기를 원한다면 \makecell이 아니라 p{width} 열, 세로 가운데가 필요하면 arraym{width}를 쓰는 것이 맞습니다.

document.tex
\usepackage{makecell}
% ...
\begin{tabular}{lc}
  \hline
  \thead{Item} & \thead{Year on year\\(\%)} \\
  \hline
  Revenue & \makecell[r]{+8.2\\(record high)} \\
  \hline
\end{tabular}

어떤 도구를 언제 쓸까

선택은 단순합니다. 가로로 가로지르면 \multicolumn, 세로로 가로지르면 \multirow, 직사각형이면 둘을 함께(안쪽에 \multirow), 한 칸 안에서 줄만 나누고 싶을 때만 \makecell 입니다. 긴 문장을 폭에 맞춰 줄바꿈하고 싶다면 답은 이 중 어느 것도 아니고 p{width} 열의 일입니다. 그리고 병합이 들어간 표를 다 썼다면 반드시 PDF를 보고 세 가지를 확인하세요. \multirow 아래 셀을 비우는 것을 잊지 않았는지(글자가 겹쳐 찍히지 않았는지), \multirow 상자가 블록 아래로 삐져나오지 않았는지(nrows를 늘리거나 빈 행을 추가), 그리고 선이 병합 셀을 가로지르지 않는지(\hline\cline이나 \cmidrule로 교체). 이 셋으로 실제로 일어나는 사고의 대부분이 정리됩니다.