반응형
public String correctEnglishTypo(TypoVo typoVo) {
List<String> correctedWords = new ArrayList<>();
int choCount = 0; int joongCount = 0; int jongCount = 0;
String englishTypo = typoVo.getKeyword(); //"DnlsehDNDptJQKFMStkrwp";
String koreanLetters = convertEnglishToKorean(englishTypo); // 변환된 한글 자/모 집합
/** 초성 / 중성 / 종성 분리 **/
for(int i = 0; i < koreanLetters.length(); i++) {
boolean isCurrentJoong = false; // 중성
boolean isChoJoong = false;
String currentLetter = String.valueOf(koreanLetters.charAt(i)); // 현) 자/모
String nextLetter = ""; // 다음) 자/모
String secondNextLetter = ""; // 다다음) 자/모
int beforeIndex = i - 1;
int nextIndex = i + 1;
int secondNextIndex = i + 2;
/** 마지막인덱스 -1 범위에 속할 경우만 다음 값을 가져온다 **/
if(isWithinBounds(i + 1, koreanLetters.length())) {
nextLetter = String.valueOf(koreanLetters.charAt(i + 1));
}
/** 마지막인덱스 -2 범위에 속할 경우만 다음 값을 가져온다 **/
if(isWithinBounds(i + 2, koreanLetters.length())) {
secondNextLetter = String.valueOf(koreanLetters.charAt(i + 2));
}
/** 중성 체크 **/
for(String JOONG : Korean.JOONGS) {
isCurrentJoong = (currentLetter.equals(JOONG))? true : false;
/** (초성 + 중성)의 단어인지 체크 **/
if(isCurrentJoong) {
isChoJoong = checkChoJoong(nextLetter, secondNextLetter);
}
/** (초성 + 중성)의 단어일 경우 해당 단어 추가 후 초기화 **/
if(isChoJoong && isCurrentJoong) {
correctedWords.add(koreanLetters.substring(beforeIndex, nextIndex));
choCount = 0; joongCount = 0; jongCount = 0;
}
/** (초성 + 중성 + 종성)의 단어일 경우 **/
if(isChoJoong == false && isCurrentJoong) {
joongCount = 1;
break;
}
}
/** 종성 체크 **/
for(String jong : Korean.JONGS) {
// 종성에 포함되는가?
boolean isContainsJong = (currentLetter.equals(jong))? true : false;
// 종성에 포함되면서 초성이 나온 경우는 종성 [초성과 종성의 겹치는 단어가 존재하기 때문에 체크 필요]
boolean isJong = (choCount == 1 && isContainsJong) ? true : false;
if(isJong) { jongCount = 1; break; }
}
/** 초성 체크 **/
for(String cho : Korean.CHOS) {
// 초성에 포함되는가?
boolean isContainsCho = (currentLetter.equals(cho))? true : false;
// 초성에 포함되면서 초성이 한번도 안 나온 경우는 초성 [초성과 종성의 겹치는 단어가 존재하기 때문에 체크 필요]
boolean isCho = (choCount == 0 && joongCount == 0 && isContainsCho) ? true : false;
if(isCho) { choCount = 1; break; }
}
/** 초성 + 중성 + 종성의 단어인 경우 조합 **/
if((choCount == 1 && joongCount == 1 && jongCount == 1)) {
correctedWords.add(koreanLetters.substring(i - 2, i + 1)); // [초 + 중 + 종] 값 가져오기
choCount = 0; joongCount = 0; jongCount = 0; // 한글자가 완성되어 초기화
}
/** 마지막 글자인 경우 (초성 + 중성) **/
boolean isLastChoJoong = nextIndex == koreanLetters.length()
&& secondNextLetter.equals("")
&& nextLetter.equals("")
&& isCurrentJoong == true
&& choCount == 1 && joongCount == 1 && jongCount == 0 ? true : false;
/** 마지막 글자인 경우 (초성 + 중성 + 종성) **/
boolean isLastChoJoongJong = secondNextIndex == koreanLetters.length()
&& secondNextLetter.equals("")
&& isCurrentJoong == true
&& choCount == 1 && joongCount == 1 && jongCount == 0 ? true : false;
if (isLastChoJoong) {
correctedWords.add(koreanLetters.substring(beforeIndex, nextIndex));
break;
}else if (isLastChoJoongJong) {
correctedWords.add(koreanLetters.substring(beforeIndex, secondNextIndex));
break;
}
}
StringBuilder words = new StringBuilder();
/** 자/모 합쳐서 단어 생성 **/
for(String correctWord : correctedWords) {
int cho = 0; int joong = 0; int jong = 0;
/** 한글자 자/모 **/
for(int i = 0; i < correctWord.length(); i++) {
String letter = Character.valueOf(correctWord.charAt(i)).toString();
if(i == 0) cho = (int) Korean.CHO_CONVERT_MAP.get(letter);
if(i == 1) joong = (int) Korean.JOONG_CONVERT_MAP.get(letter);
if(i == 2) jong = (int) Korean.JONG_MAP.get(letter);
}
// 자/모 합치기 공식
char word = (char) ((cho * 21 + joong) * 28 + jong + Korean.HANGUL_BASE);
words.append(word);
}
return words.toString();
// 1. 한글자씩 나눈다 (종성인 경우 분리)
// 2. 계산식으로 합친 한글자로 변환
// 3. 한글자 변환된 항목 합치기
// * 완전 이상한 오타인 경우 무시 정상적인 오타만 취급
// char a = ((초성 * 21 + 중성) * 28 + (종성) + 0xAC00)
// char a = ((3 * 21 + 8) * 28 + 4 + 0xAC00);
// System.out.println(a);
}
/**
* @param nextLetter - 다음 자/모
* @param secondNextLetter - 다다음 자/모
* @return 초성/중성 여부
*/
private boolean checkChoJoong(String nextLetter, String secondNextLetter) {
boolean isChoJoong = false;
/** 종성 체크 (초성 + 중성으로 끝나는 단어인지 체크) **/
for(String JONG_CHAR : Korean.JONGS) {
// 두번째 자/모가 중성인가?
boolean isSecondNextJoong = checkJoong(secondNextLetter);
// 다음 자/모가 종성인가?
boolean isNextJong = (nextLetter.equals(JONG_CHAR))? true : false;
if(isNextJong == false && isSecondNextJoong) {
isChoJoong = true;
break;
}
}
return isChoJoong;
}
/**
* @param secondNextLetter - 다다음 자/모
* @return 다다음 자/모 중성 여부
*/
private boolean checkJoong(String secondNextLetter) {
boolean isSecondNextJoong = false;
for(String Joong : Korean.JOONGS) {
isSecondNextJoong = (secondNextLetter.equals(Joong))? true : false;
if(isSecondNextJoong) break;
}
return isSecondNextJoong;
}
/**
* @param index - 현재 인덱스
* @param length - Array 및 String 인덱스의 전체 크기
* @return 정상 범위 체크 (out of bounds 체크)
*/
private boolean isWithinBounds(int index, int length) {
return index >= 0 && index < length;
}
/**
* @param englishTypo - 영문 오타
* @return 영문 오타를 한글로 변환 (rk → ㄱㅏ)
*/
private String convertEnglishToKorean(String englishTypo) {
StringBuilder korean = new StringBuilder(englishTypo);
String volew = "";
/** 이중모음 변환 **/
for (Map.Entry<String, String> entry : Korean.DOUBLE_VOWELS_KOREAN_MAP.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
korean.replace(0, korean.length(), korean.toString().replace(key, value));
}
/** 단모음 변환 **/
for (Map.Entry<String, String> entry : Korean.SINGLE_VOWELS_KOREAN_MAP.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
korean.replace(0, korean.length(), korean.toString().replace(key, value));
}
/** 쌍자음 변환 **/
for (Map.Entry<String, String> entry : Korean.DOUBLE_CONSONANTS_KOREAN_MAP.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
int isContain = korean.indexOf(key);
// 다다음 글자가 모음이 아니여야 쌍자음 변환
if(isContain != -1) {
try {volew = String.valueOf(korean.charAt(isContain + 2));}
catch(Exception e) {volew = String.valueOf(korean.charAt(isContain + 1));}
boolean hasNextVolew = Pattern.matches(koreanRegex, volew);
if(!hasNextVolew) korean.replace(0, korean.length(), korean.toString().replace(key, value));
}
}
/** 단자음 변환 **/
for (Map.Entry<String, String> entry : Korean.SINGLE_CONSONANTS_KOREAN_MAP.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
korean.replace(0, korean.length(), korean.toString().replace(key, value));
}
return korean.toString();
}
반응형
'[Java] > [Java Code]' 카테고리의 다른 글
[Java Code] 자바로 구현한 다양한 캡차 (모자이크, 숫자 더하기, 같은 색 맞추기, 가위바위보) (0) | 2023.05.31 |
---|---|
[Java Code] 자바 주민등록번호 랜덤 생성 (윤년 고려 X) (0) | 2023.05.30 |
[Java Code] yyyymmdd 날짜 계산하기, HHmmss 시간 계산하기 (두 날짜 또는 시간 빠른 순서 찾기) (0) | 2022.12.01 |
[Java Code] ini 설정 파일 읽기 (0) | 2022.11.05 |
[Java Code] OS, HostName(호스트네임), IP(아이피) 구하기 (1) | 2022.10.11 |