본문 바로가기
IT 톺아보기/이런저런 공부

한글 오토마타 만들기 - 3

by 파초우 2023. 1. 18.
반응형

문자열 변환하기

문자열을 변환하는 작업은 한글로 변환하면서 해당 문자가 초성인지, 중성인지, 종성인지 판단하는 것도 중요하다.

이를 구분하기 위해 5가지로 분류할 수 있는데,

자음만 있는 경우 -> c

초성인 경우 -> l

모음인 경우 -> v

종성인 경우 -> t

로 지정해주고 나머지는 그대로 값을 넣어준다.

def MakeHangeul(words: str) -> str:
    # ----- 중략 -----

    # 입력 받은 값을 저장하고 단어 조합하기 위한 값을 저장하는 변수
    result, result_state = "", []
    idx, n = 0, len(words)

    # 입력 받은 것을 index에 따라 저장을
    # 초성: l, 모음: v, 종성: t, 자음만: c 로 분류하며 저장
    while idx < n:
        word = words[idx]
        # 기호가 있는 경우 그냥 저장
        if word in "0123456789`~!@#$%^&*()_+-=[]{};':\"\\|,./<>? ":
            result += word
            result_state.append(word)

이렇게 result와 result_state에 값과 상태를 저장하는데 영어 알파벳이 아닌 경우, 그냥 저장을 진행한다.

그게 아닌 경우에는 아래와 같이 작업을 한다.

# 키보드 누른 값이 변환 가능한 것이면 조건문 실행
if keyval[word] != 0:
    ch = keyval[word]
    # 자음 입력 받았을 때
    if ch < 0x314f:
        # 이중 자음 받침일 경우
        if result_state and (ord(result[-1]), ch) in double_jong.keys():
            jong = double_jong[(ord(result[-1]), ch)]
            result = result[:-1] + jong
            idx += 1
            continue
            # 현재 이전에 입력 받은 문자가 모음이면
            # 종성(t) 추가, 아니면 단자음(c) 추가
        elif result_state and result_state[-1] == "v":
            result_state.append("t")
        else:
            result_state.append("c")
            # 모음 입력 받았을 때
        else:
            if result_state:
                # 종성 값이 있는 경우
                if result[-1] in double_jong_num.keys():
                    jong = double_jong_num[result[-1]]
                    result = result[:-1] + jong + chr(ch)
                    result_state += ["l", "v"]
                    idx += 1
                    continue
                    # 모음이 들어 왔을 때, 앞의 단자음을 초성으로 변환
                elif result_state[-1] in ["c", "t"]:
                    result_state[-1] = "l"
                    # 이중 종성 이 들어왔을 경우, 변환
                elif (ord(result[-1]), ch) in double_jung.keys():
                    jung = double_jung[(ord(result[-1]), ch)]
                    result = result[:-1] + jung
                    idx += 1
                    continue
                    result_state.append("v")
                    result += chr(ch)

이제 자음과 모음을 입력 받았을 경우로 나뉘는데,

자음을 받았을 경우,

​ 빈 문자열이거나 특수 기호가 마지막에 들어 왔으면 result에 그냥 입력하고 result_state에는 "c"를 추가한다.

​ 빈 문자열이 아니고 앞의 문자와 조합했을 때, 이중 종성이 만들어지는 것이면 이중 종성으로 만들어주고 result_state는 따로 추가해주지 않는다.

​ 마지막으로 입력받은 문자가 모음인 경우에는 result에 자음을 추가하고 종성인 "t"를 추가해주는 식으로 처리한다.

여기서 핵심이라고 생각되는 것은 문자를 추가하는 데 있어 앞의 문자를 보고 이것이 초성 / 종성 / 단자음을 판단하는 것이 핵심이라고 생각된다.

모음을 받았을 경우,

​ 모음 같은 경우는 자신에 대한 변화는 없지만, 앞/뒤 문자에 대한 변화를 주는 데 초점을 맞췃다.

​ 마지막에 입력받은 문자가 종성이면 result_state를 초성인 "l"로 변환해주고 중성인 "v"를 추가해준다.

​ 마지막에 입력받은 문자가 이중 자음인 경우에는 해당 문자를 분리 해주고 result_state에는 초성인 "l"과 모음인 "v"를 추가해준다.


이렇게 작업 해주고 마지막에 공백을 추가하여 완전히 출력될 수 있도록 만들어 준다.

전체 코드를 보면,

def MakeHangeul(words: str) -> str:

    # 영어를 한글로 변환하기 위한 dict
    # ------------------------------ start ------------------------------
    keyval = {
        "A": 0, "B": 0, "C": 0, "D": 0, "E": 0x3138,
        "F": 0, "G": 0, "H": 0, "I": 0, "J": 0, "K": 0,
        "L": 0, "M": 0, "N": 0, "O": 0x3152, "P": 0x3156,
        "Q": 0x3143, "R": 0x3132, "S": 0, "T": 0x3146,
        "U": 0, "V": 0, "W": 0x3149, "X": 0, "Y": 0, "Z": 0,
        "a": 0x3141, "b": 0x3160, "c": 0x314a, "d": 0x3147,
        "e": 0x3137, "f": 0x3139, "g": 0x314e, "h": 0x3157,
        "i": 0x3151, "j": 0x3153, "k": 0x314f, "l": 0x3163,
        "m": 0x3161, "n": 0x315c, "o": 0x3150, "p": 0x3154,
        "q": 0x3142, "r": 0x3131, "s": 0x3134, "t": 0x3145,
        "u": 0x3155, "v": 0x314d, "w": 0x3148, "x": 0x314c,
        "y": 0x315b, "z": 0x314b
    }

    double_jong: dict = {
        (12593, 12613): chr(0x3133), (12596, 12616): chr(0x3135), # ㄳ ㄵ
        (12596, 12622): chr(0x3136), (12601, 12593): chr(0x313a), # ㄶ ㄺ
        (12601, 12609): chr(0x313b), (12601, 12610): chr(0x313c), # ㄻ ㄼ
        (12601, 12613): chr(0x313d), (12601, 12620): chr(0x313e), # ㄽ ㄾ
        (12601, 12621): chr(0x313f), (12601, 12622): chr(0x3140), # ㄿ ㅀ
        (12610, 12613): chr(0x3144) # ㅄ
    }
    double_jong_num = {
        "ㄳ": "ㄱㅅ", "ㄵ": "ㄴㅈ",
        "ㄶ": "ㄴㅎ", "ㄺ": "ㄹㄱ",
        "ㄻ": "ㄹㅁ", "ㄼ": "ㄹㅂ",
        "ㄽ": "ㄹㅅ", "ㄾ": "ㄹㅌ",
        "ㄿ": "ㄹㅍ", "ㅀ": "ㄹㅎ",
        "ㅄ": "ㅂㅅ"
    }

    double_jung = {
        # ㅘ ㅙ ㅚ ㅝ ㅞ ㅟ ㅢ
        (12631, 12623): chr(12633), (12631, 12624): chr(12632),
        (12631, 12643): chr(12634), (12636, 12627): chr(12637),
        (12636, 12628): chr(12638), (12636, 12643): chr(12639),
        (12641, 12643): chr(12642)
    }
    # ------------------------------ end ------------------------------

    # 입력 받은 값을 저장하고 단어 조합하기 위한 값을 저장하는 변수
    result, result_state = "", []
    idx, n = 0, len(words)

    # 입력 받은 것을 index에 따라 저장을
    # 초성: l, 모음: v, 종성: t, 자음만: c 로 분류하며 저장
    while idx < n:
        word = words[idx]
        # 기호가 있는 경우 그냥 저장
        if word in "0123456789`~!@#$%^&*()_+-=[]{};':\"\\|,./<>? ":
            result += word
            result_state.append(word)
        else:
            # 키보드 누른 값이 변환 가능한 것이면 조건문 실행
            if keyval[word] != 0:
                ch = keyval[word]
                # 자음 입력 받았을 때
                if ch < 0x314f:
                    # 이중 자음 받침일 경우
                    if result_state and (ord(result[-1]), ch) in double_jong.keys():
                        jong = double_jong[(ord(result[-1]), ch)]
                        result = result[:-1] + jong
                        idx += 1
                        continue
                    # 현재 이전에 입력 받은 문자가 모음이면
                    # 종성(t) 추가, 아니면 단자음(c) 추가
                    elif result_state and result_state[-1] == "v":
                        result_state.append("t")
                    else:
                        result_state.append("c")
                # 모음 입력 받았을 때
                else:
                    if result_state:
                        # 종성 값이 있는 경우
                        if result[-1] in double_jong_num.keys():
                            jong = double_jong_num[result[-1]]
                            result = result[:-1] + jong + chr(ch)
                            result_state += ["l", "v"]
                            idx += 1
                            continue
                        # 모음이 들어 왔을 때, 앞의 단자음을 초성으로 변환
                        elif result_state[-1] in ["c", "t"]:
                            result_state[-1] = "l"
                        # 이중 종성 이 들어왔을 경우, 변환
                        elif (ord(result[-1]), ch) in double_jung.keys():
                            jung = double_jung[(ord(result[-1]), ch)]
                            result = result[:-1] + jung
                            idx += 1
                            continue
                    result_state.append("v")
                result += chr(ch)
        idx += 1
    # 한 단어만 입력되었을 때, 출력이 안되는 케이스 방지를 위해 설정
    result_state.append('')
    result += ' '

    return MappingHangeul(result, result_state)

이제 변환된 문자열을 MappingHangeul 함수를 통해 변환해주면 된다.

반응형