0. 계기
오픈소스 기여에 관심은 있었지만, 혼자 이슈를 찾고 방향을 설정하는 것이 부담스러워
6주간 멘토링을 제공하는 오픈소스 컨트리뷰션 아카데미에 지원했습니다.
여러 프로젝트 중 Rust로 작성된 점자 변환 라이브러리 Braillify를 선택했습니다.
Rust는 처음이었지만, 텍스트를 구조적으로 파싱하는 문제라는 점에서
당시 수강 중이던 컴파일러 수업(정규식, 토큰 처리)의 내용을 실제로 적용해볼 수 있을 것이라 판단했습니다.
프로젝트를 살펴보던 중,
한국 점자 규정 중 제47항(분수 표기)이 아직 구현되지 않은 상태임을 확인했습니다.
명세가 비교적 명확하면서도 입력 형식이 다양해
규정 해석과 구조 설계를 함께 경험할 수 있는 과제라 판단해
해당 항목을 직접 구현하기로 결정했습니다.
1. 구현 개요
먼저 한국 점자 규정 제47항을 분석해 요구사항을 정리했습니다.
제47항 분수는 분수표 ⠌(12)을 사용하여 분모, 분수표, 분자 순으로 적고, 대분수는 정수와 분수를 붙여 적는다. [붙임] 분수를 표시하는 빗금(/)은 ⠸⠌(5612)으로 적고, 순서는 묵자를 따른다.
도출한 요구사항은 다음과 같습니다.
- 일반 분수: 분모 → 분수표(12) → 분자
- 문맥 내 분수: 분자 → 빗금(5612) → 분모 (숫자 뒤 슬래시)
- 대분수: 정수와 분수를 붙여서 표기
- LaTeX 분수(
$\frac{3}{4}$), 유니코드 분수(⅔) 등 다양한 입력 형식 지원
제47항의 핵심은 분수의 표기 순서가 문맥에 따라 달라진다는 점이었습니다.
이에 따라 단순 문자열 치환이 아닌,
입력 형식과 주변 문맥을 해석하는 로직이 필요했습니다.
구현 목표는 다음과 같았습니다.
- 분수 유형(일반 / 문맥 내 / 대분수) 정확한 구분
- 다양한 입력 형식을 하나의 처리 흐름으로 통합
- 규정 변경이나 확장에도 대응 가능한 구조 설계
fraction.rs 모듈을 추가하고,분수 유형별 인코딩 로직을 분리해 구현했습니다.
2. 구현 내용
유니코드 정규화를 활용한 분수 처리 일반화
⅔, ¾처럼 하나의 문자로 표현된 분수가 존재합니다.이들을 개별적으로 처리하는 대신,
유니코드 표준을 활용해 입력 자체를 일반화하고자 했습니다.
NFKD 정규화를 적용하면
유니코드 분수 문자는 다음과 같이 분해됩니다.
⅔ → '2' + '⁄' + '3'
이를 기반으로 정규식을 적용해
모든 유니코드 분수를 동일한 파이프라인에서 처리할 수 있도록 구현했습니다.
let normalized: String = c.nfkd().collect();
// ⅔ → 2⁄3
let re = Regex::new(r"^(\d+)⁄(\d+)$").unwrap();
이 방식은 특정 문자 목록에 의존하지 않으며, 새로운 유니코드 분수 문자가 추가되더라도 별도의 예외 처리 없이 대응할 수 있는 구조입니다.
정규식 기반 문맥 인식 로직
2/3은 분수지만, 12/25는 날짜일 수 있습니다.
한국 점자 규정에서는 문맥 내 분수와 일반 분수의 인코딩 순서가 다르기 때문에,
이를 정확히 구분하는 것이 중요했습니다.단순 숫자 패턴 매칭이 아닌,
- 앞뒤 토큰과의 관계
- 날짜로 해석될 가능성
- 범위 표현(
1/4~1/8) 여부
를 함께 고려하는 정규식 기반 문맥 판단 로직을 구현했습니다.
if !looks_like_date(word, prev_word, next_word) {
encode_fraction_in_context(...)
}
이 과정에서 컴파일러 수업에서 배운 정규 표현식과 토큰 단위 처리 개념을 실제 서비스 코드에 적용해볼 수 있었습니다.
3. 사용한 의존성과 선택 이유
이번 구현에서는 문제를 일반화된 방식으로 처리하기 위해 아래 의존성을 추가했습니다.
unicode-normalization
유니코드 분수 문자를 표준에 따라 NFKD 정규화로 분해하기 위해 사용했습니다. 특정 문자 목록에 의존하지 않고, 모든 호환 분수 문자를 동일한 로직으로 처리할 수 있었습니다.
regex
분수, 날짜, 범위 표현 등 숫자 패턴을 문맥에 따라 구분하기 위해 사용했습니다. 규칙을 명시적으로 표현할 수 있어 점자 규정의 조건을 코드로 옮기기에 적합했습니다.
once_cell
정규식을 반복 컴파일하지 않도록 캐싱하기 위해 사용했습니다. 문맥 판단 로직을 여러 번 호출하더라도 성능 저하 없이 안정적으로 동작하도록 했습니다.
4. 성과
- 한국 점자 규정 제47항(분수 표기) 구현
- 유니코드 정규화 기반의 확장 가능한 분수 처리 구조 설계
- PR #100 메인 브랜치 머지
- Codecov 기준 테스트 커버리지 100% 달성
5. 회고
이번 기여는 규모가 큰 기능은 아니었지만, 명세를 정확히 해석하고 이를 일반화된 코드로 옮기는 경험을 할 수 있었습니다.
특히 하드코딩으로 문제를 해결하기보다, 유니코드 표준과 정규식을 활용해 입력 자체를 일반화하는 접근이 장기적으로 유지보수에 더 적합하다는 것을 배웠습니다.
또한 처음 사용하는 언어(Rust)와 낯선 도메인(점자 규정)에서도 문서를 기반으로 요구사항을 정리하고 단계적으로 구현해 나가면 충분히 의미 있는 기여를 할 수 있다는 자신감을 얻었습니다.