구두 부호 프로파일
구두 부호 정규화는 명시적으로 켜는 기능이며, 한자가 없는 입력에도 적용됩니다. 독음 선택과 주석 지시가 끝난 뒤, 렌더링 전에 실행됩니다. 언어 프리셋, 사전, 렌더링 모드와 독립적입니다.
세로쓰기 프로파일은 명시적인 종서 문자를 출력합니다. CSS의 쓰기 방향이나 폰트는 설정하지 않습니다.
프로파일 선택
두 JavaScript 바인딩 모두 같은 옵션을 받습니다:
CLI에서는 --punctuation modern을 사용합니다. 커스텀 JSON 설정은
--punctuation-profile profile.json으로 읽습니다. 두 플래그는 함께 쓸 수
없습니다.
커스텀 설정
base는 생략하면 preserve입니다. 생략한 역할은 기저 프로파일을 상속하고,
명시적인 null은 그 역할의 입력을 유지합니다. JavaScript의 undefined 속성은
바인딩에 전달하기 전에 생략합니다.
이 객체를 JavaScript의 punctuation으로 전달하거나 CLI용 파일로 저장합니다.
Rust에서는 PunctuationProfile의 공개 필드를 StopStyle, DelimiterStyle로
설정합니다. serde 기능을 켜면 같은 설정을 PunctuationConfig로 읽고
resolve()로 검증할 수 있습니다. 직접 만든 프로파일도 builder.build()에서
검증합니다.
각 부호는 Unicode 스칼라 하나여야 합니다. 여는 부호는 Unicode 17.0의 Ps/Pi,
닫는 부호는 Pe/Pf 분류여야 하며, 쉼표와 마침표는 나머지 구두점/기호 분류를
받습니다. 서로 다른 역할의 출력이나 다른 역할의 입력 부호와 충돌하면 거부합니다.
공백, 제어 문자, 글자, 숫자, <, >, &, U+FFFD도 거부합니다. 미지의
프로파일명, 필드, 공백 정책은 오류입니다. 고정된 입력 집합 밖의 커스텀 출력은
다음 변환에서 새 입력 양식으로 추론하지 않습니다.
after는 preserve, remove, single입니다. U+0020만 바꾸며 줄바꿈, 탭,
줄바꿈 없는 공백, 전각 공백은 유지합니다. single은 보통 내용과 여는 부호 앞에
공백 하나를 두고, 닫는 부호, 블록/줄 경계, EOF 앞에서는 제거합니다. 애매한
기호나 보존 경계 앞에서는 기존 공백을 유지하고 새 공백을 넣지 않습니다.
투명한 인라인 범위를 건너뛰어 공통 외부 위치에 공백을 놓되, 구조 이벤트를
256개 넘게 보류하면 기존 공백만 유지합니다.
converter.options.punctuation은 네 역할이 모두 있는 심층 동결된 복사본입니다.
보존하는 역할은 null입니다.
입력 판별과 보호 범위
어떤 출력 프로파일이든 동일한 쉼표/마침표 입력을 인식합니다. ASCII, 전각,
표의문자용, 종서 형식을 포함합니다. 인용 부호는 〈〉, 《》, 「」,
『』, 그 종서 형식과 U+2329/U+232A를 받지만, 수학용 U+27E8/U+27E9는
제외합니다. 각 부호를 독립적으로 바꾸며 짝을 수복하지 않습니다. <> 같은
ASCII 대용 표기, 보통 따옴표, 대시, 줄임표는 추론하지 않습니다.
숫자 사이의 ASCII/전각 쉼표와 마침표, 두 개 이상 연속된 마침표, Latin
문자/숫자에 인접한 ASCII/전각 마침표는 보호합니다. ASCII/전각 쉼표도 양쪽이
영숫자이거나, 앞이 영숫자이고 뒤가 공백과 Latin 문자이면 보호합니다.
Hello, world, 1,000, 3.14, example.com은 유지하지만
IMF, 세계은행은 정규화할 수 있습니다. 대소문자를 구분하지 않는 http://,
https://, mailto:, www. 구간은 Unicode 공백이나 구조/주석 경계까지
보호합니다.
Latin 보호는 Unicode Latin 스크립트의 문자를 포함하며, 결합 문자를 지나도
기저 문자의 문맥을 유지합니다. single 공백에서는 결합 문자·변형 선택자·
format 제어 문자 앞의 기존 공백을 유지하되 새로 넣지 않으므로, 구두 기호와
그 뒤의 속접 문자 사이를 새 공백으로 분리하지 않습니다.
HTML과 Markdown
HTML 텍스트에서는 WHATWG 이름식/십진/16진 문자 참조를 인식합니다. 허용된
세미콜론 생략과 수치 치환 규칙도 적용합니다. 바꾸지 않는 참조는 원문 표기를
유지합니다. 정규화 대상 부호와 공백만 리터럴과 같이 처리하며, 한 번만
디코딩하므로 &period;는 보통 텍스트, <script>는 마크업이 아닙니다.
⟨/⟩은 수학용이므로 대상 밖입니다. 속성, 코드, 외국어 범위 등의
보존 영역은 유지합니다. 원문의 ruby와 미지의 인라인 요소는 공백 추론의 경계로
다룹니다. 알려진 블록·리스트·테이블 요소는 문맥 공백을 제거하며, 이 구두점
경계 분류는 주해 창을 바꾸거나 CSS를 해석하지 않습니다. 새로 출력하는 ;, #,
!, ?, /는 인접 원문과 문자 참조를 재구성하지 않도록 수치 참조로
이스케이프합니다.
엔티티 디코딩은 정규화 단계에서만 사용합니다. 엔티티로 쓴 한자나 구두점을 독음 엔진에 다시 전달하지 않으므로, 표기만 다른 입력의 독음 선택까지 같다고 보증하지 않습니다. 미완성 참조는 텍스트 청크 사이에서 유지합니다. 수치 참조의 선행 0은 길이 제한이 없으므로, 처리 시간은 선형이지만 원문 보존에 필요한 버퍼는 길어질 수 있습니다.
Markdown 텍스트는 리더가 이미 디코딩했으므로 다시 디코딩하지 않습니다.
생 HTML과 이미지는 보호합니다. 정규화가 켜지면 보통 텍스트의 ASCII 구두점과
soft break 전 말미 공백을 수치 참조로 출력해, 새 목록/링크/hard break 등을
만들지 않습니다. 강조는 로컬 <em>, <strong>, <del> 태그로 출력해
부호 변환 후에도 의미를 유지합니다. 자동 링크의 라벨이 바뀌면 원래 목적지와
제목을 유지하는 보통 링크로 내보냅니다. 따라서 Markdown 원문 표기는 달라질 수
있지만 렌더링 구조는 보존합니다.
이스케이프한 표기는 호스팅 사이트의 URL·멘션·이슈 참조 자동 링크를 끌 수 있습니다. 목적지를 유지해야 한다면 명시적 Markdown 링크나 CommonMark 자동 링크를 사용합니다. 이러한 호스트 고유 확장은 파서가 지원하는 GFM 범위 밖입니다.
저수준 파이프라인
PunctuationNormalizer는 주석 정책 후, Renderer 전의 OutputToken을
받습니다. 상류의 finish()를 모두 비운 뒤 정규화의 finish()를 호출합니다.
I/O flush는 EOF가 아닙니다. Annotated 내용과 Verbatim은 바꾸지 않습니다.
Converter::convert_tokens()는 리터럴 텍스트용입니다. HTML 토큰에는
convert_tokens_with_codec(tokens, HtmlPunctuationTextCodec::new())와
converter.html_reader_options()를 사용해야 짝 없는 닫는 태그도 보호합니다.
루트 없는 HTML 조각도 코덱이 필요합니다. Markdown 이터레이터를 직접
직렬화한다면
write_markdown_with_options(tokens, converter.markdown_write_options())를
사용합니다. 버퍼식 편의 메서드는 이 옵션들을 자동으로 선택합니다.