본문 바로가기
업무자동화/파이썬-아래아한글 자동화 기초

현재 위치 글자모양에 "진하게"가 적용되어 있는지 확인하는 방법

by 회사원코딩 2020. 12. 7.

자동화 하다 보면 이런 상황을 종종 만납니다. 

특정 위치, 혹은 특정 문구를 가진 구간을 선택해서 "진하게"를 적용해야 하는데,
일괄적으로 모든 검색구간에 hwp.Run("CharShapeBold")를 실행해버리면
기존에 진하게 되어 있던 구간들은 모두 "진하게"가 풀려버리잖아?

이런 경우 해결하는 방법입니다.

우선 코드실행 화면은 아래와 같습니다.

조항번호 재정렬 및 조항명 진하게 하는 코드 실행화면

조항번호 재정렬 및 조항명 진하게 하는 코드 실행화면(움짤)

현재 캐럿이 위치해 있는 글자 혹은 선택영역의 속성적용여부를 알아내는 코드는 아래와 같습니다.

Act = hwp.CreateAction("CharShape")  # "글자모양" 액션 생성
Set = Act.CreateSet()  # 해당 세트 생성
Act.GetDefault(Set)  # 세트 초기화(Set의 파라미터에 현재 문서의 값을 적용)
print(Set.Item("Bold"))  # 1이면 "진하게", 0이면 "보통", None이면 "일부 진하게"

위 코드의 "CharShape" 문자열이나, "Bold" 등 액션아이디나 아이템아이디 문자열을 어떻게 찾는지 문의 주셨는데,

1. 저는 공식문서 Action Table.hwp 에서 "글자 모양" 또는 "글자모양"을 검색해서 "CharShape"을 찾고,

2. 공식문서 ParameterSet Table.hwp을 열어서 "CharShape"로 검색해서 "Bold" 아이템을 찾습니다.

틈틈이 검색하다 보면 공식문서 찾는 게 익숙해지고, 속도도 빨라집니다.

하여튼, 위 코드를 적용해서 업데이트한 "조항 재정렬 및 진하게" 코드는 아래와 같습니다.

from tkinter import Tk
from tkinter.filedialog import askopenfilename
import re
import win32com.client as win32


######################## 이 부분이 업데이트됨 #############################
def 조항제목진하게():
    Act = hwp.CreateAction("CharShape")  # 액션테이블에서 "글자 모양" 검색, 액션아이디에서 "CharShape" 찾음
    Set = Act.CreateSet()  # 세트 생성
    Act.GetDefault(Set)  # 세트 초기화(Set의 파라미터에 현재 문서의 값을 적용)
    if Set.Item("Bold") == 1:  # 파라미터셋테이블에서 "CharShape" 검색, 아이템아이디에서 "Bold" 찾음
        return
    else:
        hwp.HAction.GetDefault("RepeatFind", hwp.HParameterSet.HFindReplace.HSet)
        hwp.HParameterSet.HFindReplace.FindString = ")"
        hwp.HParameterSet.HFindReplace.Direction = hwp.FindDir("Forward")
        hwp.HParameterSet.HFindReplace.IgnoreMessage = 1
        hwp.HParameterSet.HFindReplace.FindType = 1
        hwp.HAction.Execute("RepeatFind", hwp.HParameterSet.HFindReplace.HSet)
        hwp.HAction.Run("MoveRight")
        hwp.HAction.Run("MoveLeft")
        hwp.HAction.Run("MoveSelLineBegin")
        hwp.HAction.Run("CharShapeBold")
        hwp.HAction.Run("MoveLineBegin")
###########################################################################

def hwp_find_replace(find_string, replace_string):
    hwp.Run("MoveSelNextWord")
    hwp.HAction.GetDefault("ExecReplace", hwp.HParameterSet.HFindReplace.HSet)  # 한/글 특성상 부득이하게 두두번번 실실행행
    hwp.HParameterSet.HFindReplace.Direction = hwp.FindDir("Forward")
    hwp.HParameterSet.HFindReplace.FindString = find_string
    hwp.HParameterSet.HFindReplace.ReplaceString = replace_string
    hwp.HParameterSet.HFindReplace.ReplaceMode = 1
    hwp.HParameterSet.HFindReplace.IgnoreMessage = 1
    hwp.HParameterSet.HFindReplace.FindType = 1
    hwp.HAction.Execute("ExecReplace", hwp.HParameterSet.HFindReplace.HSet)
    hwp.HAction.GetDefault("ExecReplace", hwp.HParameterSet.HFindReplace.HSet)
    hwp.HParameterSet.HFindReplace.Direction = hwp.FindDir("Forward")
    hwp.HParameterSet.HFindReplace.FindString = find_string
    hwp.HParameterSet.HFindReplace.ReplaceString = replace_string
    hwp.HParameterSet.HFindReplace.ReplaceMode = 1
    hwp.HParameterSet.HFindReplace.IgnoreMessage = 1
    hwp.HParameterSet.HFindReplace.FindType = 1
    hwp.HAction.Execute("ExecReplace", hwp.HParameterSet.HFindReplace.HSet)
    hwp.Run("Cancel")


def hwp_init(filename):
    hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
    hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")
    hwp.Open(filename)
    hwp.XHwpWindows.Item(0).Visible = True
    hwp.HAction.Run("FrameFullScreen")
    return hwp


def hwp_replace(hwp):
    hwp.InitScan()
    조항번호 = 1
    while True:
        text = hwp.GetText()
        if text[0] == 1:
            break
        else:
            if re.match(r"^제\d+조\(?", text[1]) and text[1].startswith(f"제{조항번호}조("):
                hwp.MovePos(201)  # moveScanPos : GetText() 실행 후 위치로 이동한다.
                조항제목진하게()  ########################### 이렇게 한 줄 삽입
                조항번호 += 1
                continue
            elif re.match(r"^제\d+조\(?", text[1]) and not text[1].startswith(f"제{조항번호}조("):
                hwp.MovePos(201)  # moveScanPos : GetText() 실행 후 위치로 이동한다.
                조항제목진하게()  ############################# 또 이렇게 한 줄 삽입
                hwp_find_replace(re.match(r"^제\d+조\(?", text[1]).group(0), f"제{조항번호}조(")
                조항번호 = 1
                hwp.InitScan()
            else:
                pass
    hwp.ReleaseScan()
    hwp.MovePos(2)


if __name__ == '__main__':
    root = Tk()
    filename = askopenfilename()
    root.destroy()

    hwp = hwp_init(filename=filename)
    hwp_replace(hwp)
728x90
반응형

댓글3

  • 별포스정 2021.05.16 14:51 신고

    안녕하세요~~
    위 예제 코드에서 궁금한 점이 2가지 있어서 문의남깁니다.
    1. hwp.MovePos(201) # moveScanPos : GetText() 실행 후 위치로 이동한다.라고 되어 있는데 이게 정확히 무슨의미인지 이해가 안됩니다.
    2. if text[0] == 1: 조건에서 "1"은 리스트의 마지막이라고 알고 있습니다. 홈피의 건축관리법 시행령을 적용해서 실행시 아무런 문제없이
    정상적으로 동작 및 종료 되었지만, 빈페이지에다 조항 몇 개만 복사해서 시험해보니 text[0]==1이라는 조건에 안걸려 무한반복되는 현상이
    생겼습니다. 그래서 리스트의 마지막이라는 것이 무슨 의미인지 좀 궁금합니다.
    답글

    • 회사원코딩 2021.05.16 19:58 신고

      1. MovePos 메서드는 정수를 인자로 받습니다. 예제에서 들어간 201의 의미는 API매뉴얼에서 검색해보면 "moveScanPos"라고 명시되어 있으며, 이 뜻은 InitScan() 후 GetText메서드 반복 실행으로 문자열 탐색 중, 현재 탐색된 위치로 캐럿을 이동하라는 의미입니다. 예제코드를 보시면 문맥이 이해되실 겁니다.

      2. 가끔 특수한 경우가 있나봅니다. 그런 경우라면 마지막에 디버깅이나 print문을 통해서 어떤 정수를 리턴하고 있는지 확인해보시고 코드를 수정해 주시기 바랍니다. 정수1이 무조건 리스트의 마지막이 아닌 경우도 있었던 것 같기도 합니다... 특히 탐색중 문자열이 수정되거나 하면 즉시 다른 정수를 리턴하기도 하고요. 저도 그때그때 땜빵식 코드를 넣느라 잘 기억이 안 나네요;; 이따 한 번 테스트해보겠습니다^^;

      행복한 하루 되세요!!!

  • 별포스정 2021.05.16 20:35 신고

    답변 감사드립니다.~~
    일단 2번에 대해 임시방편으로, 문장 마지막이후 리턴값이 0으로 계속 반복되어서 제 임의로 GetText()의 리턴값이 0이 20번이상 연속해서 반복되면 강제로 break문이 실행되도록 해서 프로그램을 종료하도록 했습니다.^^
    답글