- 분야: FE
- 기술 스택: React · TypeScript
문제와 원인
skctMathMarkdown의 수식 후보 문자 집합과 판별 조건에 유니코드 아래첨자가 빠져 aₙ₋₁을 수식으로 고르지 못했다. 표기 변환도 _n과 _(...)만 처리해 유니코드 아래첨자가 원문 그대로 표시됐다.
수정 전 코드
proseMath
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
function proseMath(text: string) {
return text.replace(/[|√A-Za-z0-9α-ωΑ-Ω][A-Za-z0-9α-ωΑ-Ω_\^⁰¹²³⁴⁵⁶⁷⁸⁹=+−×÷*\/≥≤≠<>|(). \t{}-]*/gu, raw => {
const expression = raw.trimEnd().replace(/[.,]+$/u, "");
if (!/(?:_[A-Za-z\d(]|\^[A-Za-z\d-]|[⁰¹²³⁴⁵⁶⁷⁸⁹√≥≤≠]|[\w)]\s*[=+×÷−]\s*[\w(|]|\d\s*\/\s*\d)/u.test(expression)
|| /^\d{4}\/\d{1,2}\/\d{1,2}$/u.test(expression)) return raw;
return `$${notation(expression)}$${raw.slice(expression.length)}`;
});
}
notation
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
.replace(/_\(([^()]+)\)/gu, "_{$1}")
.replace(/_([A-Za-zα-ωΑ-Ω]|\d+)/gu, "_{$1}")
수정 후 코드
proseMath
수식 후보 추출·판별에 아래첨자 숫자와 n·k·i·j, 아래첨자 +·−를 추가했다. 영문·그리스 문자 뒤의 아래첨자를 한 구간으로 읽고 대응값을 합쳐 aₙ₋₁을 a_{n-1}로 변환한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
function proseMath(text: string) {
return text.replace(/[|√A-Za-z0-9α-ωΑ-Ω][A-Za-z0-9α-ωΑ-Ω_\^⁰¹²³⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉₊₋ₙₖᵢⱼ=+−×÷*\/≥≤≠<>|(). \t{}-]*/gu, raw => {
const expression = raw.trimEnd().replace(/[.,]+$/u, "");
if (!/(?:_[A-Za-z\d(]|\^[A-Za-z\d-]|[⁰¹²³⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉ₙₖᵢⱼ√≥≤≠]|[\w)]\s*[=+×÷−]\s*[\w(|]|\d\s*\/\s*\d)/u.test(expression)
|| /^\d{4}\/\d{1,2}\/\d{1,2}$/u.test(expression)) return raw;
return `$${notation(expression)}$${raw.slice(expression.length)}`;
});
}
notation
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const subscripts: Record<string, string> = {
"₀": "0", "₁": "1", "₂": "2", "₃": "3", "₄": "4",
"₅": "5", "₆": "6", "₇": "7", "₈": "8", "₉": "9",
"₊": "+", "₋": "-", "ₙ": "n", "ₖ": "k", "ᵢ": "i", "ⱼ": "j",
};
return expression
.replace(
/([A-Za-zα-ωΑ-Ω])([₀₁₂₃₄₅₆₇₈₉₊₋ₙₖᵢⱼ]+)/gu,
(_, base: string, subscript: string) =>
`${base}_{${[...subscript].map(char => subscripts[char]).join("")}}`,
)
.replace(/_\(([^()]+)\)/gu, "_{$1}")
.replace(/_([A-Za-zα-ωΑ-Ω]|\d+)/gu, "_{$1}");
저장된 문제 원문은 유지하고 표시용 Markdown을 변환한다. 인라인 코드·코드 블록·기존 수식 구분자 내부와 날짜를 보호하는 기존 처리도 유지했다.
검증 결과
원본 전후 skctMathMarkdown에 같은 6개 문자열을 넣어 반환된 Markdown을 비교했다. 아래첨자 3개는 0/3개(0%)에서 3/3개(100%)로, 전체 기대 문자열 일치는 3/6개에서 6/6개로 바뀌었다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
| 입력 | 수정 전 | 수정 후·기대 Markdown |
|---|---|---|
aₙ | aₙ | $a_{n}$ |
aₙ₋₁ | aₙ₋₁ | $a_{n-1}$ |
xₖ₊₁ | xₖ₊₁ | $x_{k+1}$ |
a_n | $a_{n}$ | $a_{n}$ |
인라인 코드 `aₙ` | `aₙ` | `aₙ` |
날짜 2026/9/30 | 2026/9/30 | 2026/9/30 |
기존 표기·코드·날짜 3/3개 조건은 전후 같은 결과를 유지했다.
같은 문자열 6개를 원본 전후 함수에 다시 전달해 로컬 Node에서 각 1회 실행했다. 아래첨자 3개가 LaTeX로 변환됐고 기존 표기·인라인 코드·날짜 입력은 그대로 남았다.