import 'dart:math'; class HangulUtils { static const int FIRST_HANGUL = 44032; // '가' static const int LAST_HANGUL = 55203; // '힣' static const List CHOSUNG_LIST = [ 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' ]; static const List JUNGSUNG_LIST = [ 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ' ]; static const List JONGSUNG_LIST = [ '', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' ]; static final Random _random = Random(); /// 단어를 입력받아, 랜덤한 한 글자를 아주 살짝 변형해서 반환 static String generateSimilarWord(String original) { if (original.isEmpty) return original; // 1. 한글인 문자들의 인덱스만 찾음 List 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; } }