가이드 / Finipage / 문제 해결

HTML 한글 깨짐 해결: EUC-KR 파일을 UTF-8로 바꾸는 법

Qorlize 팀 작성 · 마지막 검토

Finipage 가이드 · HTML 파일을 코드 없이 고치는 편집기. Finipage 열기

예전 회사 홈페이지 파일이나 옛 게시판에서 내려받은 HTML을 열었더니 한글이 ÇѱÛ처럼 나오거나, 글자마다 �가 찍혀 있는 경우가 있습니다. 파일 속 바이트는 그대로이고 브라우저가 다른 규칙으로 읽고 있을 뿐이라, 순서만 지키면 원래 글자를 되살릴 수 있습니다.

깨진 모양을 보면 원인이 보입니다

텍스트 파일은 바이트의 나열이고, 인코딩은 바이트를 글자로 바꾸는 표입니다. 2010년 무렵 이전에 만든 한국어 페이지는 대부분 EUC-KR이나 그 확장판인 CP949(MS949, 한국어 Windows의 "ANSI")로 저장돼 있습니다. 요즘 파일은 거의 UTF-8입니다. 같은 낱말도 두 방식은 전혀 다르게 저장합니다.

인코딩"한글"의 바이트한 글자당
EUC-KR / CP949C7 D1 B1 DB2바이트
UTF-8ED 95 9C EA B8 803바이트
  • ÇѱÛ처럼 악센트 붙은 로마자: EUC-KR 파일을 서유럽 인코딩(Windows-1252)으로 읽은 경우입니다. 바이트 하나가 글자 하나로 읽혔습니다.
  • �: EUC-KR 파일을 UTF-8로 읽은 경우입니다. UTF-8 규칙에 맞지 않는 바이트라 브라우저가 대체 문자로 바꿉니다.
  • 엉뚱한 한자와 뜻 없는 한글 사이사이에 ?나 �가 섞임: 반대로 UTF-8 파일을 EUC-KR로 읽은 경우입니다. 3바이트씩 묶여야 할 바이트가 2바이트씩 잘못 묶이고, CP949에 없는 조합은 대체 문자가 됩니다.

참고로 EUC-KR은 완성형 한글 2,350자만 담고, CP949가 나머지를 더해 11,172자를 모두 표현합니다. "똠", "햏" 같은 글자가 일부 프로그램에서만 깨지는 이유입니다. 브라우저는 euc-kr이라는 이름을 CP949로 처리하므로 웹에서는 둘을 같은 것으로 봐도 됩니다.

인코딩은 누가 정하나: BOM, 서버 헤더, meta 태그

브라우저는 처음부터 추측하지 않습니다. HTML 표준에 따라 다음 순서로 인코딩을 정합니다.

  1. BOM: 파일 맨 앞이 EF BB BF 세 바이트면 무조건 UTF-8로 읽습니다.
  2. 서버가 보낸 Content-Type 헤더: text/html; charset=euc-kr처럼 서버가 지정하면 파일 안의 선언보다 우선합니다.
  3. meta 태그: <meta charset="utf-8"> 또는 옛 형식인 <meta http-equiv="Content-Type" content="text/html; charset=euc-kr">. 파일 앞 1,024바이트 안에 있어야 하므로 <head> 바로 아래에 둡니다. 자리는 HTML 파일의 구조에서 확인할 수 있습니다.

셋 다 없을 때에야 브라우저가 바이트 모양과 브라우저·운영체제 언어를 근거로 추측하며, 그 결과는 브라우저마다 다를 수 있습니다.

"내 PC에서는 멀쩡한데 서버에 올리면 깨진다"는 문제가 대부분 여기서 생깁니다. 내 PC에서 파일로 열면 서버 헤더가 없으니 meta 태그가 결정합니다. 그런데 Apache의 AddDefaultCharset UTF-8이나 nginx의 charset utf-8; 설정이 된 서버에 올리면 헤더가 EUC-KR meta 태그를 이겨 버립니다.

meta 태그는 이름표일 뿐 변환 장치가 아닙니다. 바이트가 EUC-KR인 파일에 charset="utf-8"만 적으면 브라우저가 더 확신을 갖고 잘못 읽을 뿐입니다.

파일의 실제 인코딩 확인하기

  • VS Code: 오른쪽 아래 상태 표시줄에 인코딩이 나옵니다. 기본 설정에서는 UTF-8로 가정하므로, 설정에서 files.autoGuessEncoding을 켜야 EUC-KR을 알아봅니다.
  • Windows 메모장: 오른쪽 아래에 UTF-8, BOM이 붙은 UTF-8, ANSI 같은 인코딩 이름이 표시됩니다. 한국어 Windows에서 ANSI는 CP949입니다.
  • 브라우저: 페이지에서 F12를 누르고 Console에 document.characterSet을 입력하면 브라우저가 실제로 적용한 인코딩이 나옵니다. Network 탭에서 HTML 요청을 누르면 서버가 보낸 Content-Type도 볼 수 있습니다.
  • 바이트 직접 보기: 헥스 뷰어로 열었을 때 한글이 EA~ED로 시작하는 3바이트 묶음이면 UTF-8, 첫 바이트가 대개 B0~C8인 2바이트 묶음이면 EUC-KR입니다.

UTF-8로 변환하기

원리는 하나입니다. 원래 인코딩으로 제대로 읽은 다음 UTF-8로 다시 저장합니다. 반드시 사본으로 먼저 해 보십시오.

VS Code

  1. 파일을 열고 상태 표시줄의 인코딩 이름을 누릅니다.
  2. Reopen with Encoding(인코딩하여 다시 열기)에서 Korean (EUC-KR)을 고릅니다. 글자가 바로 보여야 합니다. 그래도 깨지면 다른 인코딩이니 저장하지 말고 다시 확인합니다.
  3. 인코딩 이름을 다시 누르고 Save with Encoding(인코딩하여 저장)에서 UTF-8을 고릅니다.

Windows 메모장

한국어 Windows라면 메모장이 CP949 파일을 대개 제대로 엽니다. 글자를 확인한 뒤 파일 > 다른 이름으로 저장에서 저장 버튼 옆 인코딩 목록을 UTF-8로 바꿔 저장합니다. 여기서 기준은 화면 표시 언어가 아니라 제어판 > 국가 또는 지역 > 관리자 옵션 탭의 유니코드를 지원하지 않는 프로그램용 언어(시스템 로캘)입니다. 이 값이 한국어가 아닌 PC에서는 처음부터 깨진 채로 열리고, 그대로 저장하면 깨진 글자가 굳어 버리므로 VS Code를 쓰십시오.

Finipage

내용까지 고칠 생각이라면 Finipage 편집기로 열어도 됩니다. EUC-KR 같은 옛 인코딩을 열 때 자동으로 판별해 한글이 깨지지 않고, 저장할 때 UTF-8로 쓰면서 meta charset도 UTF-8로 바꿔 줍니다. 파일은 브라우저 안에서만 처리되고 어디에도 올라가지 않습니다.

meta 태그 정리와 BOM 주의

변환이 끝나면 파일 위쪽을 확인합니다. charset=euc-kr이 남아 있다면 <meta charset="utf-8">로 바꿉니다. VS Code와 메모장은 바이트만 바꾸고 HTML 내용은 건드리지 않습니다. 지금은 괜찮아 보여도 파일로 열거나 호스팅을 옮기면 옛 선언이 다시 문제를 일으킵니다.

메모장에서 저장할 때는 BOM이 붙은 UTF-8보다 그냥 UTF-8을 고르십시오. 페이지 맨 앞의 BOM은 브라우저에 해가 없습니다. 하지만 PHP include 등으로 다른 파일 중간에 끼워 넣으면 그 세 바이트가 출력 한가운데 들어가, 빈 줄 같은 틈을 만들거나 서유럽 인코딩으로 읽힌 페이지에서 로 찍히고, PHP에서는 "headers already sent" 오류를 냅니다.

서버를 직접 관리한다면 헤더도 UTF-8로 맞춰 주십시오.

페이지와 함께 쓰이는 파일도 같이 바꿔야 합니다. include하는 머리글·바닥글, 한글 문자열이 든 .js 파일, 페이지가 읽어 오는 CSV 등입니다. 하나라도 EUC-KR로 남으면 그 부분만 다시 깨집니다.

다음에 할 일

글자가 제대로 보이면 문구나 배치를 고치고 싶어질 겁니다. 태그를 직접 만지지 않는 방법은 코드 없이 HTML 파일 고치기에 정리했습니다. 같은 페이지에서 이미지도 안 보인다면 HTML 파일에서 이미지가 안 보일 때를 보십시오.

내 파일로 바로 해 보려면 Finipage 편집기를 여세요. 브라우저에서 돌아가고 파일은 내 기기 밖으로 나가지 않습니다.