문서 작업 가이드
Unicode 계산 단위별 텍스트 길이 제한 검증
필드가 확장 자소군·코드 포인트·UTF-16·UTF-8 바이트·단어·줄 중 무엇을 제한하는지 확인하고 문자를 자르지 않은 채 실제 경계를 시험합니다.
작성 및 검수 SimpleWebUtils게시일: 검토일:
이 작업 흐름을 검증한 방법
“UTF-8 31바이트 표시 이름 필드 시험” 문서 입력을 단어 수 세기에 그대로 넣었습니다. 수행 순서는 “원본 증거를 정확히 보존하기”, “가능한 모든 단위 측정하기”였고 브라우저 결과를 예시 출력과 대조했습니다. 실패 경계는 “문자를 JavaScript length로 가정하기”, “임의의 문자열 slice로 자르기” 두 항목으로 나눠 검토했습니다.
NFC fixture는 grapheme 6개·code point 12개·UTF-16 unit 16개·UTF-8 31바이트였고, 분해형은 정규화 전 32바이트라 문서화된 NFC 저장 계약에서만 허용됐습니다.
문제 상황
‘최대 30자’라는 문구는 시스템이 문자를 정의하지 않으면 불완전합니다. 연결 이모지 하나도 확장 자소군은 1개지만 코드 포인트와 UTF-16 코드 유닛은 여러 개이고 UTF-8에서는 더 많은 바이트를 차지합니다. 눈에 같아 보이는 정규화 표현도 바이트·코드 포인트 수가 다를 수 있습니다. 클라이언트와 API·데이터베이스·출판 규정이 서로 다른 단위를 쓰면 뒤늦은 거부, 잘못된 잘림, 유일성 충돌, 불일치한 집계가 생깁니다. 실제 제한을 소유한 시스템의 단위를 확인하고 그 경계를 직접 실행해야 합니다.
이럴 때 사용하세요
- API, 데이터베이스 열, 폼, 메시지, 파일명 또는 가져오기에 길이 제한이 있을 때
- 다국어 필드에 악센트, 한글, CJK, 이모지, 결합 문자, 오른쪽에서 왼쪽으로 쓰는 문자가 있을 때
- 브라우저와 서버가 같은 값의 초과 여부를 다르게 판단할 때
- 마이그레이션·정규화·인코딩 변경이 코드 포인트나 바이트 수를 바꿀 수 있을 때
- 출판사나 학교가 단어·문자·줄·읽기 시간을 규정하고 제출 근거가 필요할 때
단계
- 1단계
제한을 소유한 구성요소 찾기
프로토콜, 스키마, 데이터베이스 타입, 폼 계약 또는 제출 지침을 읽습니다. 단위, 경곗값 포함 여부, 문자 인코딩, 정규화 순서, 줄바꿈 처리, 초과 시 잘림 또는 거부 동작을 기록합니다. UI placeholder는 권위 있는 계약이 아닙니다.
- 2단계
원본 증거를 정확히 보존하기
원문을 보관하고 파일·네트워크 본문이라면 원본 바이트와 선언 인코딩도 남깁니다. 실제 원본을 기록하기 전에 정규화, trim, 줄바꿈 교체, 보이지 않는 문자 제거를 하지 않습니다.
- 3단계
대표 경계 fixture 만들기
ASCII, 조합형·분해형 악센트, 한글, 공백 없는 CJK, 연결 이모지, 결합 문자, CRLF와 LF, 마지막 줄바꿈, 허용된 형식 문자를 포함합니다. 디코딩 손실이 지나가지 않도록 의도적인 U+FFFD 사례도 추가합니다.
- 4단계
가능한 모든 단위 측정하기
각 fixture를 단어 수 세기로 분석해 확장 자소군, 코드 포인트, UTF-16 코드 유닛, UTF-8 바이트, 단어형 세그먼트, 논리 줄을 기록합니다. 대상이 요구하는 형식을 비교할 때만 Unicode 정규화를 사용하고 원본 증거를 덮어쓰지 않습니다.
- 5단계
숨은 문자와 줄바꿈 차이 조사하기
형식 문자와 U+FFFD 경고를 검토합니다. CRLF·LF·CR·마지막 빈 줄·문단 경계를 줄바꿈 증거로 설명합니다. joiner는 이모지나 문자 체계에 의미가 있을 수 있으므로 필드 정책이 금지한 문자만 제거합니다.
- 6단계
제한값 아래·정확히·위에서 실행하기
권위 있는 단위가 제한값-1, 제한값, 제한값+1인 fixture를 제출합니다. API·데이터베이스 직접 경로와 일반 클라이언트를 모두 시험하고, 실패가 명시적이며 surrogate pair·결합 시퀀스·연결 이모지 중간을 자르지 않는지 확인합니다.
- 7단계
결과를 다시 읽고 계약으로 남기기
저장·전송된 값을 다시 읽어 원문, 바이트, 정규화 형식, 줄바꿈을 승인된 fixture와 비교합니다. 규칙, fixture, 실제 오류, 소프트웨어 버전을 자동 회귀 테스트에 기록해 런타임·스키마 변경이 계약을 몰래 바꾸지 못하게 합니다.
예시
UTF-8 31바이트 표시 이름 필드 시험
입력
계약: UTF-8 최대 31바이트, 저장 시 NFC, 자르지 않고 거부.
Fixture A: Café 👨👩👧👦 (NFC)
Fixture B: Cafe + U+0301 + 공백 + 가족 이모지 (NFD 표현)출력
Fixture A: 확장 자소군 6개, 코드 포인트 12개, UTF-16 유닛 16개, UTF-8 31바이트이므로 승인.
Fixture B 정규화 전: 확장 자소군 6개, 코드 포인트 13개, UTF-16 유닛 17개, UTF-8 32바이트. 문서화된 NFC가 31바이트 검사 전에 적용되는지 확인하고 저장된 NFC 값을 다시 읽습니다.흔한 실수
문자를 JavaScript length로 가정하기
JavaScript length는 UTF-16 코드 유닛입니다. 대상 계약이 그 표현을 명시했을 때만 맞으며 확장 자소군·코드 포인트·인코딩 바이트를 대신할 수 없습니다.
임의의 문자열 slice로 자르기
코드 유닛 slice는 surrogate pair를 나눌 수 있고 코드 포인트 slice도 결합 문자나 연결 이모지를 분리할 수 있습니다. 가능하면 거부하고, 잘라야 한다면 제품이 지정한 분할·정규화 정책을 따릅니다.
문서에 없는 계층에서 정규화하기
정규화는 바이트·코드 포인트 수를 바꾸며 호환 정규화는 의미도 바꿀 수 있습니다. 검증·유일성 검사와의 순서를 포함해 대상이 문서화한 형식만 적용합니다.
제한 근처를 ASCII로만 시험하기
ASCII에서는 확장 자소군·코드 포인트·UTF-16·UTF-8 수가 같아 보입니다. 다국어 사용자에게 발생할 가능성이 큰 실패를 드러내지 못합니다.
클라이언트 통과를 최종 증거로 믿기
실제 동작은 API·데이터베이스·큐·출판 시스템이 결정합니다. 브라우저 보고서로 정밀 fixture를 만들 수 있지만 대상 경계와 왕복은 반드시 실행해야 합니다.
자주 묻는 질문
사용자에게 보이는 글자 제한에는 어떤 단위가 적절한가요?
확장 자소군이 사용자가 보는 문자에 가장 가까운 경우가 많지만 별도의 바이트·저장 안전 한계도 필요합니다. 두 규칙을 명시하고 하나를 다른 하나처럼 조용히 사용하지 마세요.
Unicode 정규화 전과 후 중 언제 길이를 검사해야 하나요?
대상 계약을 따릅니다. NFC로 저장하는 시스템이라면 최종 정규화 값을 검사하는 흐름이 일관될 수 있지만 유일성·서명·보안 검사도 같은 순서를 써야 하며 원본 증거는 남겨야 합니다.
동등한 텍스트가 바이트 경계를 넘을 수 있는 이유는 무엇인가요?
미리 조합된 코드 포인트와 기본 문자+결합 문자는 같아 보이면서 코드 포인트와 UTF-8 바이트 수가 다를 수 있습니다. 예시의 NFC·NFD 표현이 그 차이를 보여 줍니다.
Intl.Segmenter가 학교나 출판사의 단어 수를 정의할 수 있나요?
하이픈, 인용, 숫자, CJK 분할, 제외 구역을 다루는 기관 규칙을 하나의 런타임 알고리즘이 대신할 수 없습니다. 재현 가능한 근거로 사용하고 명시된 편집 규칙과 대조하세요.
계산 전에 0폭 문자를 제거해도 안전한가요?
필드 정책이 금지하는 정확한 코드 포인트를 지정했을 때만 안전합니다. joiner는 의미가 있을 수 있으므로 일괄 정리 대신 역할과 결과 자소군을 확인하세요.
자동 회귀 테스트에는 무엇을 넣어야 하나요?
관련 문자 체계·인코딩 경계별 이름 있는 fixture, 예상 단위 수, 아래·정확히·위 결과, 정규화 순서, 정확한 오류 동작, 실제 저장소·API 왕복 검증을 보존합니다.