Unicode NFD → NFC 정규화 도구

맥에서 쪼개진 한글, 한 줄로 고칩니다.

맥에서 만든 파일명, 맥에서 설정한 git 이름이 다른 환경에서 ㅎㅗㅇㄱㅣㄹㄷㅗㅇ처럼 자모로 쪼개져 보인 적 있나요? unorm은 macOS의 NFD(분해형) 한글을 표준 NFC(완성형)로 되돌리는 가벼운 Node.js CLI이자 라이브러리입니다.

npx @nkcroft/unorm@latest --fix-git-user
  • 설치 없이 npx로 실행
  • macOS · Linux · Windows
  • 의존성 2개
  • MIT 라이선스

보기엔 같아도, 컴퓨터에겐 다른 글자입니다

macOS는 한글을 초성·중성·종성 자모로 분해한 NFD로 저장하는 경우가 많고, Windows·Linux·웹은 완성형 음절인 NFC를 씁니다.

NFD · 분해형

ㅎㅗㅇㄱㅣㄹㄷㅗㅇ

9 code points
U+1112 U+1169 U+11BC U+1100 U+1175 U+11AF U+1103 U+1169 U+11BC

macOS에서 입력·저장된 형태입니다. 자모를 합치지 못하는 환경에서는 글자가 따로따로 보입니다.

NFC · 완성형

홍길동

3 code points
U+D64D U+AE38 U+B3D9

어디서나 같은 글자로 인식되는 표준 형태입니다. unorm이 이 형태로 바꿔 줍니다.

  • 같은 "홍길동"으로 검색해도 찾지 못합니다.
  • git 커밋 작성자가 같은 사람인데 두 명으로 갈립니다.
  • 압축을 풀거나 다른 OS로 옮기면 파일명이 자모로 깨집니다.

git 작성자 이름, 3단계로 고치기

맥에서 git config --global user.name을 한글로 설정했다면 NFD로 저장되어 있을 수 있습니다. 먼저 진단하고, 필요할 때만 고칩니다.

  1. 진단 (읽기 전용)

    현재 이름의 정규화 형식, 글자 수, 코드 포인트를 보여 줍니다. 아무것도 바꾸지 않습니다.

    npx @nkcroft/unorm@latest --test-git-user
  2. 수정

    NFD가 감지되면 NFC로 바꿔 저장하고, 다시 읽어서 제대로 저장됐는지 확인합니다.

    npx @nkcroft/unorm@latest --fix-git-user
  3. 확인

    이후 커밋부터 작성자 이름이 NFC로 기록됩니다. 다시 진단하면 ✓가 표시됩니다.

    git log -1 --format='%an'
실행 예시: --fix-git-user
$ npx @nkcroft/unorm@latest --fix-git-user
Successfully normalized git user.name to NFC!
  Before : 홍길동  NFD ⚠ (decomposed), 9 code points  \u1112\u1169\u11BC\u1100\u1175\u11AF\u1103\u1169\u11BC
  After  : 홍길동  NFC ✓, 3 code points  홍길동
  Glyphs are identical (3); only the encoding changed.

파일, 파이프, 코드까지

git 이름만이 아닙니다. 텍스트 파일과 스트림, Node.js 코드 어디서든 같은 방식으로 정규화합니다.

CLI 파이프 · 파일 · 문자열

# 전역 설치 (선택)
npm install -g @nkcroft/unorm

# 파이프로 변환 (기본값 NFC)
cat mac_nfd_text.txt | unorm > win_nfc_text.txt

# 파일을 직접 지정
unorm -i mac_nfd_text.txt -o win_nfc_text.txt -f NFC

# 문자열 변환과 상세 분석
unorm "한글"
unorm -t "$(git config --global user.name)"

라이브러리 ESM · CommonJS · TypeScript

// npm install @nkcroft/unorm
import { normalizeString } from '@nkcroft/unorm'

const nfd = '한글'.normalize('NFD')
normalizeString(nfd)          // '한글' (NFC, 기본값)
normalizeString('한글', 'NFD') // 분해형

스트림 대용량 파일

청크 경계에서 자모·결합문자가 잘려도 전체를 한 번에 변환한 것과 같은 결과를 냅니다.

import { createReadStream, createWriteStream } from 'node:fs'
import { NormalizeStream } from '@nkcroft/unorm'

createReadStream('input-nfd.txt')
  .pipe(new NormalizeStream({ form: 'NFC' }))
  .pipe(createWriteStream('output-nfc.txt'))

작고, 정확하고, 안전하게

필요한 일만 하는 도구를 목표로 만들었습니다.

  • 설치 없이 실행

    npx 한 줄로 바로 진단·수정합니다. 런타임 의존성은 commander와 picocolors 두 개뿐입니다.

  • 정확한 진단

    형식(NFC/NFD/NFKC/NFKD), 눈에 보이는 글자 수, 코드 포인트, 이스케이프를 나란히 보여 줍니다.

  • 스트림 경계 안전

    대용량 파일을 청크로 나눠 처리해도 가+ᆨ 같은 조합이 끊기지 않습니다.

  • 안전한 git 수정

    셸을 거치지 않고 git을 호출하고, 저장 후 다시 읽어 검증합니다. 이미 NFC면 아무것도 바꾸지 않습니다.

  • 모든 플랫폼

    macOS·Linux·Windows에서 Node.js 20.12 이상이면 동작합니다.

  • 라이브러리로도

    ESM, CommonJS, TypeScript 타입을 함께 제공합니다. 문자열 함수와 Transform 스트림을 그대로 가져다 쓰세요.

자주 묻는 질문

문제가 생기면 먼저 여기를 확인해 주세요. 해결되지 않으면 GitHub 이슈로 알려 주세요.

이미 쌓인 커밋의 작성자 이름도 바뀌나요?

아니요. --fix-git-user는 전역 설정만 바꾸므로 이후 커밋부터 NFC 이름이 기록됩니다. 과거 커밋은 히스토리를 다시 쓰지 않는 한 그대로 남습니다. GitHub 등에서 두 이름을 같은 사람으로 묶으려면 .mailmap을 활용하세요.

새 맥에서 --test-git-user가 실패해요

macOS의 기본 git은 Xcode Command Line Tools가 설치되어야 동작합니다. 둘 중 하나를 설치한 뒤 다시 실행하세요. 문자열·파일 변환은 git 없이도 됩니다.

xcode-select --install   # 또는: brew install git
unorm requires Node.js 20.12.0 or newer가 나와요

오래된 Homebrew·시스템 Node.js를 쓰고 있다는 뜻입니다. Node.js 20.12 이상으로 올려 주세요.

brew upgrade node        # 또는: nvm install --lts
npx @nkcroft/unorm 실행 시 엉뚱한 결과가 나와요

PATH에 이미 다른 unorm 실행 파일이 있으면 그것이 먼저 실행될 수 있습니다. 아래 명령으로 확인하고, 충돌하는 파일의 이름을 바꿔 주세요.

which unorm
npx @nkcroft/unorm@latest --version
unorm: command not found가 나와요

최신 npm에서는 버전을 지정하지 않으면 패키지 대신 명령을 찾으려 할 수 있습니다. @latest를 붙이거나 npm exec를 쓰세요.

npx @nkcroft/unorm@latest --version
npm exec --yes --package @nkcroft/unorm@latest -- unorm --version
NFC로 바꾸면 데이터가 손실되나요?

NFC와 NFD는 정준 등가(canonical equivalence)여서 글자의 의미와 모양은 같고 인코딩만 다릅니다. 반면 NFKC/NFKD는 호환 문자(예: fi → fi)를 바꾸므로 필요한 경우에만 사용하세요.

지금 내 git 이름부터 확인해 보세요

읽기 전용 진단이라 아무것도 바뀌지 않습니다.

npx @nkcroft/unorm@latest --test-git-user