92 lines
3.3 KiB
Dart
Raw Normal View History

2025-11-21 15:54:17 +09:00
import 'dart:math';
class HangulUtils {
static const int FIRST_HANGUL = 44032; // '가'
static const int LAST_HANGUL = 55203; // '힣'
static const List<String> CHOSUNG_LIST = [
'', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', ''
];
static const List<String> JUNGSUNG_LIST = [
'', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', ''
];
static const List<String> JONGSUNG_LIST = [
'', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', ''
];
static final Random _random = Random();
/// 단어를 입력받아, 랜덤한 한 글자를 아주 살짝 변형해서 반환
static String generateSimilarWord(String original) {
if (original.isEmpty) return original;
// 1. 한글인 문자들의 인덱스만 찾음
List<int> hangulIndices = [];
for (int i = 0; i < original.length; i++) {
int code = original.codeUnitAt(i);
if (code >= FIRST_HANGUL && code <= LAST_HANGUL) {
hangulIndices.add(i);
}
}
if (hangulIndices.isEmpty) return original; // 한글 없으면 그대로 반환
// 2. 바꿀 글자 위치 랜덤 선택
int targetIndex = hangulIndices[_random.nextInt(hangulIndices.length)];
String targetChar = original[targetIndex];
// 3. 글자 변형
String modifiedChar = _tweakHangul(targetChar);
// 4. 조합해서 반환
return original.replaceRange(targetIndex, targetIndex + 1, modifiedChar);
}
/// 한 글자를 분해해서 초/중/종성 중 하나를 살짝 바꿈
static String _tweakHangul(String char) {
int code = char.codeUnitAt(0) - FIRST_HANGUL;
int choIndex = code ~/ (21 * 28);
int jungIndex = (code % (21 * 28)) ~/ 28;
int jongIndex = code % 28;
// 무엇을 바꿀지 결정 (0:초성, 1:중성, 2:종성)
// 종성이 없는 글자('가')라면 종성을 추가하는 것도 방법이지만,
// 너무 티가 나므로 초/중성 위주로 변경
int type = _random.nextInt(3);
if (type == 0) {
// [초성 변경] 비슷한 모양으로 변경 시도
choIndex = _getSimilarIndex(choIndex, CHOSUNG_LIST.length);
} else if (type == 1) {
// [중성 변경] (ㅏ -> ㅑ, ㅗ -> ㅜ 등)
jungIndex = _getSimilarIndex(jungIndex, JUNGSUNG_LIST.length);
} else {
// [종성 변경]
jongIndex = _getSimilarIndex(jongIndex, JONGSUNG_LIST.length);
}
// 재조립
int newCode = FIRST_HANGUL + (choIndex * 21 * 28) + (jungIndex * 28) + jongIndex;
return String.fromCharCode(newCode);
}
/// 인덱스를 랜덤하게 +-1 하거나 변경하여 "비슷한" 느낌을 줌
static int _getSimilarIndex(int current, int max) {
// 단순히 랜덤이 아니라, 현재 값과 가까운 값으로 변경하면 더 헷갈림
int offset = _random.nextBool() ? 1 : -1;
int next = current + offset;
if (next < 0) next = 1;
if (next >= max) next = max - 2;
// 만약 원래랑 같아져버리면 강제로 변경
if (next == current) next = (current + 1) % max;
return next;
}
}