# 조사 앞 강조

> CommonMark 파서가 `**설정(config)**을` 의 강조를 닫지 않는 이유와 mdwire 가 읽는 규칙, 채널별 출력 방법을 정리했습니다. 다른 파서도 같은 동작을 따라 구현할 수 있습니다.

HTML: https://mdwire.minjun.dev/ko/docs/emphasis/

한국어는 조사(`을`, `는`, `이다`, `로` …)를 앞 단어에 띄우지 않고 붙입니다. 강조한 단어가 괄호, 따옴표,
백틱, 마침표, `%` 같은 구두점으로 끝나면 CommonMark 는 그 강조를 닫지 않습니다.

```text
**설정(config)**을   **"배포 금지"**는   **`git revert`**로   **끝.**이라서   **52%**다
```

CommonMark 를 따르는 파서(micromark, markdown-it, lezer, GFM)는 모두 이 별표를 글자로 남깁니다. 한 줄에
여럿이면 짝이 엇갈려 그 사이 글이 굵어집니다. LLM 은 이 모양을 자주 씁니다. 이 문서는 mdwire 가 이 모양을
읽는 규칙과 채널별 출력 방법을 정리했습니다. 다른 파서도 같은 동작을 따라 구현할 수 있습니다.

## CommonMark 가 닫지 않는 이유

닫는 `**` 는 **오른쪽 플랭킹**이어야 합니다. 앞이 공백이 아니고, 앞이 구두점이 아니거나 뒤가 공백이나 구두점이어야
합니다. `**설정(config)**을` 의 닫는 마커는 앞이 `)`(구두점)이고 뒤가 `을`(글자)이라 닫히지 않습니다. 이
규칙은 영어를 기준으로 만들어졌습니다. 영어에서는 마커 바로 뒤에 단어가 붙어 있으면 그 마커를 뒤 단어에 딸린
것으로 봅니다. 한국어에서는 그 단어가 강조한 단어의 조사입니다.

여는 쪽에도 같은 경우가 있습니다. 앞이 글자이고 뒤가 구두점인 여는 마커(`값**(합계)**`)는 왼쪽 플랭킹이
아닙니다. 다만 한국어 답변에서는 드뭅니다.

## 읽는 규칙

mdwire 는 CommonMark 에서 세 가지를 바꿔 강조를 읽습니다. 여기서 구두점은 ASCII 구두점과 LLM 이 쓰는 CJK
구두점(`，。、！？；：·…—～「」『』（）【】《》`)이고, **글자**는 모든 문자 체계의 글자와 ASCII 숫자입니다.
`①`, `🔥` 같은 기호는 글자가 아닙니다.

1. **닫기**: 같은 종류의 강조가 열려 있으면, 마커 앞 글자가 공백이 아닌 한 닫습니다. 닫는 쪽의 플랭킹
   판정은 하지 않습니다.
2. **열기**: 마커 뒤 글자가 공백이 아니고, 그 글자가 구두점이 아니거나 마커 앞 글자가 글자가 아니면
   엽니다. CommonMark 의 왼쪽 플랭킹 판정과 같지만, `①**"…"**` 는 엽니다(앞의 기호는 글자가 아닙니다).
3. **먼저 연 쪽이 진다**: 같은 종류가 이미 열려 있는데 앞이 공백이고 열 수 있는 마커가 오면 먼저 연
   마커가 짝 잃은 쪽입니다. 먼저 연 마커는 짝 없이 남고 새 마커가 강조를 엽니다. 새 마커를 닫는 쪽으로
   읽으면 강조 범위가 뒤집힙니다. `채널**이다. …⏎**신분 공개**이` 에서 실제로 이 줄바꿈 고장을 겪었습니다.

실제 글에서 규칙이 안전하게 동작하도록 두 가지를 더 지킵니다.

- 글자·숫자 뒤의 `_` 는 **열지** 않습니다(`snake_case`, `2026-04-29_제목` 은 글자로 남습니다). 닫는 쪽으로는
  읽습니다(`_진료_가`).
- 블록이 끝날 때까지 열려 있는 강조는 그 블록 끝에서 닫고 고친 것으로 셉니다. 블록을 넘어 번지지 않습니다.

강조로 잘못 읽기 쉬운 모양(`2 ** 3`, 글롭 `*`), 마스킹 번호(`4***-****`), 코드 스팬까지 다루는 전체 구현은
`crates/mdwire-core/src/inline.rs` 에, 사례는 [테스트 케이스](https://github.com/minjun0219/mdwire/tree/main/corpus/cases)
`punct-before-closing-emphasis`, `emphasis-across-linebreak`, `asterisk-is-a-letter`, `masked-number-asterisks`
에 있습니다.

## 채널별 출력

강조를 제대로 읽어도 문제가 남습니다. 출력을 렌더링하는 채널이 CommonMark 규칙을 다시 적용할 수 있기
때문입니다. 아래 표는 채널마다 측정한 결과입니다.

| 채널 | `**설정(config)**을` 을 굵게 표시하나 | 보낼 것 |
|---|---|---|
| GitHub(GFM) | 아니요. 별표가 남습니다. | `<strong>설정(config)</strong>을`. 태그는 플랭킹을 따지지 않습니다. GFM 이 읽지 못하는 짝에만 씁니다. |
| 슬랙 `markdown_text` | 아니요. 별표가 남습니다. | `**설정(config)` + U+2060 + `**을`. 닫는 마커 바로 앞에 보이지 않는 워드 조이너를 넣습니다. 공백도 구두점도 아니어서 닫는 마커가 오른쪽 플랭킹이 됩니다. 마커 **뒤**에 넣으면 소용없습니다. |
| 노션 | 예 | 그대로 둡니다. `<strong>` 은 글자로 보입니다. |
| 텔레그램 HTML · 브라우저 HTML | — | 태그로 출력하므로 문제가 생기지 않습니다. |

U+200B 대신 U+2060 을 씁니다. 둘 다 굵게 렌더링되지만 U+200B 는 그 자리에서 줄이 바뀔 수 있고 U+2060 은
그렇지 않습니다. 여는 마커가 막힌 경우에는 여는 마커 바로 뒤에 넣습니다. 실측은 2026-09-30(GitHub,
`POST /markdown`)과 2026-10-01(슬랙 `chat.postMessage`, 노션 API)에 했습니다.

어느 짝을 고칠지는 원문의 이웃 글자, 곧 여는 마커 앞 글자와 닫는 마커 뒤 글자로 양쪽의 CommonMark 플랭킹
판정을 해 보고 정합니다. 판정에 걸리는 짝만 고치고 나머지는 쓴 그대로 둡니다.
