2018년 이후의 LaTeX이라면 café의 é도, señor의 ñ도, Gauß의 ß도 원본에 그냥 입력하는 것만으로 조판됩니다. 그런데 그렇게 만든 PDF를 열고 “café”를 검색하면 한 건도 걸리지 않는 일이 있습니다. 원인은 악센트 기호 자체가 아니라 서문의 단 한 줄——fontenc 설정입니다. 이 페이지에서는 악센트가 붙은 서양어 텍스트를 입력에서 PDF 속 내용까지 하나의 흐름으로 좇습니다. 입력 인코딩, babel을 통한 언어 선언, .bib의 저자명, 그리고 hyperref의 책갈피까지, 사고는 언제나 양 끝에서 일어납니다. 악센트 명령 자체의 목록은 관련 페이지에 맡깁니다.
\usepackage[utf8]{inputenc}은 이제 쓰지 않아도 됩니다
UTF-8은 2018년부터 LaTeX의 기본 입력 인코딩입니다. inputenc을 전혀 불러오지 않고 Un café à Montréal, señor Gauß, Kovář, Łódź.이라고 쓴 문서는 TeX Live 2024의 pdfLaTeX에서 경고 하나 없이 통과합니다. LaTeX News 28(2018년)은 기본값을 “그대로 통과시키는” 방식에서 UTF-8로 바꾸었음을 기록하고, 그래서 \usepackage[utf8]{inputenc}은 더 이상 필수가 아니며 써 두어도 해가 없다고 밝히고 있습니다. 즉 inputenc utf8을 검색해 나오는 옛 해설 대부분은 이미 존재하지 않는 문제를 설명하고 있는 셈입니다.
XeLaTeX과 LuaLaTeX은 본래 UTF-8이 유일한 입력 인코딩이므로 inputenc은 처음부터 할 일이 없습니다. 다만 오류가 되지는 않습니다. TeX Live 2024에 들어 있는 inputenc.sty(2021/02/14 v1.3d)로 이 두 엔진에 inputenc을 넘기면 돌아오는 것은 Package inputenc Warning: inputenc package ignored with utf8 based engines.라는 경고이고, 컴파일은 그대로 끝까지 갑니다. 옛 서문을 LuaLaTeX으로 가져와도 멈추지 않는 이유가 이것이며, 뒤집어 말하면 “오류가 안 나니 맞다”고는 할 수 없습니다. 서문을 정리할 때 지워 두는 편이 깔끔합니다.
한 가지 곁들이자면, UTF-8이라는 부호화 방식 자체는 1992년에 켄 톰프슨과 롭 파이크가 고안한 것으로, LaTeX News 28도 그 경위를 언급합니다. TeX이 태어난 1970년대 말에는 7비트 ASCII밖에 없어서 é를 내려면 명령을 쓰는 수밖에 없었습니다. 지금 é를 그냥 칠 수 있는 것은 그 40년의 우회로가 끝났다는 뜻입니다.
pdfLaTeX이라면 \usepackage[T1]{fontenc}을 반드시 넣습니다
inputenc이 “원본의 바이트열을 어떻게 읽을지”를 정한다면, fontenc은 “글꼴의 몇 번째 자리에 어떤 글자가 있는지”를 정합니다. 기본값인 OT1은 128자 분량밖에 없고 악센트가 붙은 글자를 하나의 글자로 갖고 있지 않습니다. 그래서 é는 “e 위에 예음 부호를 겹쳐 그리는” 합성으로 출력됩니다. 겉보기는 거의 같아도 TeX이 보기에는 “글자 하나”가 아니라 “글자와 기호의 겹침”이므로, 그 낱말은 하이픈 넣기 대상에서 통째로 빠집니다(어떤 명령이 어느 부호화에서 쓰이는지는 관련 페이지의 표에 정리되어 있습니다). T1은 256자 분량이 있어 é도 ř도 ł도 하나의 글자로 갖고 있습니다.
“T1으로 하면 Computer Modern이 비트맵이 되어 PDF가 지저분해진다”는 조언을 만난다면 그것은 낡은 정보입니다. TeX Live 2024에서 \usepackage[T1]{fontenc}만 더해 만든 PDF를 pdffonts로 살펴보면 묻혀 있는 것은 cm-super에서 온 SFRM1000이고 종류는 Type 1——비트맵(Type 3)이 아닙니다. 그래도 lmodern을 더할 값어치는 있습니다. 묻히는 글꼴이 LMRoman10-Regular로 바뀌고, Latin Modern은 Computer Modern의 설계를 유니코드 시대에 맞춰 다시 그린 것이라 글자 종류의 포괄이나 글꼴 파일의 내력이 더 깔끔하기 때문입니다.
XeLaTeX과 LuaLaTeX에서는 fontenc이 나설 자리가 없습니다. 이들은 OS의 글꼴을 유니코드 그대로 다루므로 fontspec으로 서체를 고르면 악센트가 붙은 글자가 그대로 나옵니다. 즉 판단은 단순한 양자택일입니다. pdfLaTeX이면 T1(가능하면 lmodern도), Xe/LuaLaTeX이면 fontspec. 덧붙여 근래의 LaTeX 커널은 유니코드 대응표를 꽤 넓게 갖추어, pdfLaTeX + T1에서도 €・→・–・“ ”를 그대로 쳐서 경고 없이 조판할 수 있습니다. 전각 기호는 사정이 달라, 그쪽은 “서양어 조판” 페이지에서 다룹니다.
% pdfLaTeX: the two lines that matter
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern} % optional, but cleaner glyph coverage
% (no inputenc: UTF-8 has been the default since 2018)
\begin{document}
Un café à Montréal, señor Gauß, Kovář, Łódź.
\end{document}
% XeLaTeX / LuaLaTeX: no fontenc at all
% \usepackage{fontspec}
% \setmainfont{Latin Modern Roman}PDF에서 “café”가 검색되지 않을 때——글자가 둘로 나뉘어 있습니다
같은 원본 Un café à Montréal, señor Gauß, Kovář, Łódź.을 fontenc 없이(기본 OT1)와 [T1]{fontenc}을 넣고 두 번 컴파일한 뒤 pdftotext로 내용을 뽑아 부호 위치까지 보면 차이가 결정적입니다. OT1 판에서는 é가 “e” + U+0301(결합용 예음 부호)의 두 문자로 저장되어 있습니다. 그래서 PDF 뷰어에 “café”(é는 U+00E9)를 입력해도 일치하지 않습니다. 실제로 café・Montréal・Łódź를 검색하면 세 낱말 모두 0건입니다. T1 판은 같은 자리에 U+00E9・U+00E1・U+0159・U+0141・U+017A 같은 미리 조합된 한 문자가 들어 있어 세 낱말 모두 찾힙니다.
더 알기 쉬운 파손도 있습니다. 폴란드어의 Ł(빗금 친 L)은 OT1에 글자가 없어서 LaTeX은 L에 선을 겹쳐 그립니다. 눈으로는 Ł이지만 PDF에서 뽑은 문자열은 Łódź가 아니라 Lódź——빗금이 사라지고 맨 L이 되어 있습니다. 저자명이나 지명이 이 상태로 출판되면 본문은 제대로 보이는데 검색에서도, 문헌 관리 프로그램으로 복사할 때도 철자가 어긋나는 성가신 틈이 남습니다. 같은 이유로 OT1에서는 악센트가 붙은 낱말이 하이픈으로 나뉘지 않습니다(그 실측은 관련 페이지 “악센트 기호”에 있습니다).
# extract the text layer and inspect the code points
pdftotext paper.pdf - | head -1
# default OT1 -> e is followed by U+0301, a separate combining acute,
# and the bar of L is lost entirely:
# searching for "café" / "Montréal" / "Łódź" gives 0 hits
# with T1 -> precomposed U+00E9 U+00E1 U+0159 U+0141 U+017A:
# all three words are found
# and check what font actually got embedded
pdffonts paper.pdfbabel과 polyglossia로 언어를 선언하면 입력까지 달라집니다
babel에 언어를 넘기면 그 언어의 입력 단축 표기(shorthand)가 살아납니다. \usepackage[ngerman]{babel}을 넣은 문서에서는 "a "o "u "s가 각각 ä ö ü ß가 되고, 큰따옴표 단축 표기의 두 형태는 독일어의 아래·위 인용부호 „ 와 “ 를 냅니다. "-는 한 걸음 더 나아가 “여기서 나눠도 된다”는 하이픈 위치를 더해 주므로, Zucker"-dose라고 써도 출력은 Zuckerdose 그대로——표시 자체는 지면에 나오지 않습니다. 독일어 자판이 없는 환경에서 독일어를 쓰거나, 원고를 순수 ASCII로 유지하고 싶을 때 값을 합니다.
XeLaTeX・LuaLaTeX에서는 polyglossia가 같은 역할을 맡아 \setmainlanguage{german}처럼 선언합니다. 어느 쪽을 쓰든 조심할 것은 단축 표기가 "의 의미를 다시 쓴다는 점입니다. verbatim 밖의 URL이나 코드 조각, 파일 이름에서 "를 그냥 치면 뜻밖의 글자가 나올 수 있습니다. 인용부호나 외부 파일 이름이 많은 절에서는 \shorthandoff{"}로 잠시 꺼 두는 편이 확실합니다. 덧붙여 babel은 입력만이 아니라 하이픈 넣기와 언어별 조판 관례까지 바꾸는데, 그쪽은 “서양어 조판” 페이지의 몫입니다.
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
% "a "o "u "s -> a-umlaut, o-umlaut, u-umlaut, eszett
% "- -> an extra hyphenation point, invisible in the output
% Zucker"-dose still prints as one word
\shorthandoff{"} % turn the shorthands off around URLs and code.bib의 저자명——BibTeX은 É를 Z보다 뒤에 놓습니다
악센트 사고가 가장 눈에 띄는 곳은 본문이 아니라 문헌 목록입니다. 시험해 봅시다. Alpha・Ore・Zola・Zulu 네 건을 .bib에 넣되 Émile Zola와 Øystein Ore는 UTF-8 그대로 씁니다. plain.bst로 BibTeX을 돌리면 나오는 순서는 Alpha, Zulu, Zola, Ore——É와 Ø로 시작하는 두 건이 Z보다 뒤로 떨어집니다. BibTeX은 이름을 바이트열로 비교하는데, UTF-8 É의 첫 바이트가 z보다 크다는 그 이유뿐입니다. 경고도 오류도 전혀 나오지 않습니다. 같은 .bib에서 저자명만 {\'E}mile・{\O}ystein이라는 명령 표기로 바꾸면 순서는 Alpha, Ore, Zola, Zulu로 바로잡힙니다.
이 버릇에는 이유가 있습니다. TeX Live 2024에 들어 있는 BibTeX은 시작할 때 여전히 Version 0.99d라고 밝힙니다——1980년대에 Oren Patashnik이 쓴 프로그램이 40년 가까이 1.0에 이르지 못한 채 현역인 것입니다. 7비트 시대의 설계를 그대로 짊어지고 있어서 유니코드 정렬 규칙이 없습니다. 반면 biblatex + biber는 유니코드를 이해하여 같은 UTF-8 .bib를 한 글자도 고치지 않고 올바르게 정렬합니다(biber 2.19에서 확인). 따라서 실무의 판단은 둘 중 하나입니다. biber를 쓸 수 있는 투고처라면 UTF-8 그대로 두고, BibTeX을 강제받는다면 .bib만 명령 표기로 통일합니다. 어느 쪽이든 섞지 않는 것이 요체입니다. 섞인 .bib에서는 중복 검출도 정렬도 믿을 수 없습니다.
% BibTeX 0.99d + plain.bst sorts these as Alpha, Zulu, Zola, Ore
@article{a1, author = {Émile Zola}, title = {Un titre}, journal = {J}, year = {2001}}
@article{a3, author = {Øystein Ore}, title = {Another}, journal = {J}, year = {2003}}
% ...and these as Alpha, Ore, Zola, Zulu -- correct
@article{a1, author = {{\'E}mile Zola}, title = {Un titre}, journal = {J}, year = {2001}}
@article{a3, author = {{\O}ystein Ore}, title = {Another}, journal = {J}, year = {2003}}
% biblatex + biber sorts the UTF-8 form correctly with no rewriting:
% \usepackage[backend=biber]{biblatex}책갈피와 PDF 문자열——hyperref은 악센트를 통과시킵니다
PDF의 책갈피(bookmark)와 문서 정보는 본문과는 별개의 “PDF 문자열”로 기록됩니다. 예전에는 여기서 악센트가 떨어지는 것이 흔한 사고였지만 지금은 기본값이 유니코드입니다. TeX Live 2024의 hyperref 7.01h로 \section{Le café de Montréal}을 조판하면 생성되는 .out 파일에 UTF-16 바이트 순서 표시에 이어 é(U+00E9)가 그대로 들어 있고 책갈피에도 제대로 나옵니다. unicode 옵션을 손으로 더할 필요는 이제 없습니다.
다만 PDF 문자열이 본문의 모든 명령을 받아들이는 것은 아닙니다. 제목에 수식을 넣으면 로그에 Package hyperref Warning: Token not allowed in a PDF string (Unicode): removing 'math shift'가 줄줄이 찍히고, 해당 토큰은 책갈피 쪽에서 조용히 제거됩니다. 본문은 맞는데 책갈피만 알 수 없는 상태가 여기서 생깁니다. 고치는 방법은 \texorpdfstring{}{}으로, 첫 인수에는 조판용, 둘째 인수에는 책갈피용 평문을 넘깁니다. 악센트가 붙은 낱말은 둘째 인수에 그대로 써도 됩니다. PDF 문자열이 유니코드인 이상 café는 café 그대로 통과합니다.
\usepackage{hyperref}
% the log fills with "Token not allowed in a PDF string"
\section{Le café de Montréal $x^2$}
% typeset form on the left, bookmark text on the right
\section{Le café de Montréal \texorpdfstring{$x^2$}{x2}}공동 집필에 앞서 정해 둘 것
악센트 입력 방침은 원고가 커진 뒤에는 되돌리기 어려운 종류의 결정입니다. 같은 인명이 Gödel과 G\"{o}del 두 가지로 적힌 원고는 어느 쪽이든 제대로 조판되지만, 검색도 일괄 치환도 중복 확인도 모두 두 번 일이 됩니다. 게다가 일관되지 않음을 알아차리는 것은 대개 제출 직전에 문헌 목록을 훑을 때입니다. 엔진, fontenc 한 줄, .bib의 표기——이 셋을 첫 커밋에서 정해 버리는 것이 가장 값싼 길입니다.
- 본문은 UTF-8 직접 입력으로 통일합니다.
inputenc은 쓰지 않습니다. 한 줄이면 됩니다. Xe/LuaLaTeX이면fontspec, pdfLaTeX이면\usepackage[T1]{fontenc}. - 인수 시험을 한 번만 돌립니다. 만들어진 PDF에서
café와 저자명을 검색해 걸리는지 확인합니다. 걸리지 않으면fontenc줄이 빠진 것입니다. .bib는 투고처의 도구 사슬에 맞춥니다. biber를 쓸 수 있으면 UTF-8 그대로, BibTeX을 강제받으면 저자명을 모두{\'E}형식으로 통일하고 둘을 섞지 않습니다.- 제목에 수식이 들어가면
\texorpdfstring을 곁들입니다.Token not allowed in a PDF string경고는 책갈피가 망가졌다는 신호입니다. babel단축 표기를 쓴다면 URL과 코드 주위에서\shorthandoff{"}을 합니다. 따옴표의 의미가 바뀌어 있다는 사실을 잊기 쉽습니다.