본문 바로가기
아래아한글 자동화/python+hwp 중급

GetText 실행 후에 찾아가서 수정하는 방법

by 일코 2022. 2. 6.

안녕하세요?

일상의 코딩, 일코입니다.

지난 포스팅에서는,

문자열을 단락별로 탐색해서 리턴해주는

GetText라는 메서드를 소개해 드렸습니다.

2022.02.04 - [업무자동화/파이썬-아래아한글 자동화 기초] - GetText, 한/글 자동화 고급과정의 첫걸음①

 

GetText, 한/글 자동화 고급과정의 첫걸음①

안녕하세요? 일상의 코딩, 일코입니다. 이전 포스팅에서 찾기 후 매크로 몇 줄을 보태서 문제를 간단히 해결했습니다. 2022.02.03 - [업무자동화/파이썬-아래아한글 자동화 기초] - 찾기로 탐색한 단

martinii.fun

 

그런데 GetText는 의외로 싱겁습니다.

지금 탐색하고 있는 단락 상태값과, 문자열만 담백하게 리턴해줍니다.

그 문자열을 어떻게 수정해야 하는지는

내 코딩능력을 활용해야 합니다.

 

파이썬은 다행히

① 문자열 인덱싱도 간편하고

② 다양한 문자열 관련 메서드가 존재하며

③ 간결하면서도 강력한 정규식 문법이 있기 때문에 

 

굉장히 자유롭게 문자열 편집이 가능합니다.

 

반면에, 파이썬의 문자열 관련한 메서드나
정규식 등에 익숙하지 않은 분들은
"코딩으로 해결할 수 있다"는 점이
오히려 난관으로 느껴지실 수도 있겠습니다ㅜ

 

하지만 파이썬의 문자열 인덱싱이나 메서드들이

굉장히 직관적이고 간결하므로

처음 접해 보시더라도 금방 익숙해지실 겁니다.

 

그럼 시작해보겠습니다.

지난 포스팅에서 GetText를 통해 문자열을 받는 걸 보여드렸습니다.

대략 아래와 같은 화면이었습니다.

이번에는 while 문 안에 GetText를 넣고,
탐색이 끝날 때까지 반복하게 할 예정입니다.

 

다음으로 할 일은 내가 편집하고 싶은 문자열이 포함되어 있는지

파이썬에서 검색해보는 것입니다.

리턴된 문자열에 "|"가 포함되어 있는가?

 

코드는 간단하게 짜여집니다.

while True:
    인덱스, 문자열 = hwp.GetText()
    if "|" in 문자열:
        관련작업
    else:
        pass

 

이제 위의 틀 안에

본격적으로 "관련작업"을 짜넣어 볼 차례입니다.

다음과 같은 작업을 할 예정이거든요.

① 해당 위치로 직접 찾아가서
② "|"는 삭제하고
③ 그 뒤의 단어를 선택해서
④ 진하게&밑줄 서식을 적용해라.

 

위 네 개의 과정을

하나씩 차례대로 자세히 알아보겠습니다.

 

① 해당 위치로 찾아가는 코드

우선 GetText와 연동되는,

즉, GetText로 탐색한 단락의 시작점으로 이동하는 코드는

지난 포스팅에서 알려드렸듯이

hwp.MovePos(201)

입니다.

 

위의 코드를 실행하면 이런 상태가 됩니다.

(네 번째 문단, 즉 표 안에 있는 문단을 대상으로 실습하겠습니다.)

파이썬에서 탐색한 단락의 시작점으로 캐럿 이동

파이썬에서 탐색한 단락의 시작점으로 캐럿이 바로 이동하네요.

 

이제 리턴한 문자열 안에 있는 "|"의 인덱스를 알아내야 합니다.

직접 찾아가야 하니까요.

해당 문자열 안에 모든 "|"의 인덱스값을 리턴하는

가장 간편한 방법은 re.finditer입니다.

re는 파이썬에서 정규식을 활용하는 내장모듈입니다.
따로 설치는 필요없고, 임포트만 하시면 됩니다.

아래처럼 코딩하고 실행해보겠습니다.

import re


for m in re.finditer("\|", 문자열):
    print(m.start())

"|"는 정규식 메타문자 중의 하나(or연산자)이므로
역슬래시를 하나 추가해서 "\|"로 탐색했습니다.

리턴된 값은 0과 280, 두 개입니다.

본문에서 어느 위치냐면, 

입니다. 첫 번째 "|"는 시작점이니까 0이 맞는 것 같고,

두 번째 "|"의 인덱스가 280이 맞는지 한 번 캐럿을 옮겨 보겠습니다.

아래의 코드를 실행하면 됩니다.

hwp.MovePos(1, 0, 280)  # 현재 리스트, 0번 단락의 280번째 인덱스로 캐럿 이동

 

실행해보면 아래와 같이 캐럿이 이동합니다.

두 번째 "|"의 앞으로 캐럿이 정확하게 옮겨간 것을 확인했습니다.

한/글에서도 인덱스가 1이 아닌 0부터 시작하므로
파이썬의 문자열 인덱싱과 동일하게 연동이 됩니다.

 

한 가지 중요한 점이 더 남아 있습니다.

위치인덱스가 0과 280이지만,

앞쪽에서 한 글자를 지워버리면

위치인덱스가 0과 279로 바뀌게 되겠죠?

그래서 본문수정이 필요한 경우는

인덱스 리스트를 역순으로 정렬하는 과정이 필요합니다.

뒤에서부터 편집을 하면 앞쪽 인덱스가 변경되지 않으니까요.

이 부분도 간단히 수정할 수 있는데, 다음 포스팅에서 최종보완하겠습니다.

 

 

중간정리

여기까지의 작업과정만

파이썬 코드로 정리하면 아래와 같습니다.

만약 이해가 안 되는 부분이 있다면

위에서 다시 한 번 읽어보시고 오시기 바랍니다.

import re

import win32com.client as win32


hwp = win32.gencache.EnsureDispatch("hwpframe.hwpobject")  # 한/글 열기
hwp.XHwpWindows.Item(0).Visible = True  # 숨김해제
hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")  # 보안모듈 실행
hwp.Open(r"C:\Users\smj02\Desktop\food_unites_2.hwpx")  # 문서 열기


hwp.InitScan()  # 탐색 초기화
while True:
    상태값, 문자열 = hwp.GetText()
    if 상태값 in (0, 1):  # 문서 끝까지 탐색을 마쳤으면 0 또는 1 리턴
        # 상태값 0 : 텍스트 정보 없음
        # 상태값 1 : 리스트의 끝
        break  # while문 종료
    else:
        hwp.MovePos(201)
        위치리스트 = [m.start() for m in re.finditer("\|", 문자열)]
        for 위치 in 위치리스트:
            hwp.MovePos(1, 0, 위치)  # 해당 인덱스로 캐럿 이동
            # "|" 지우고 뒷단어 진하게&밑줄 적용하는 코드 추가 예정
간단하네요!

 

지난 포스팅에서는

"|"를 삭제하고 뒤의 한 단어를 선택해서

진하게&밑줄 서식을 적용하는 코드를

아래와 같이 작성해보았습니다.

def 한글_진하게밑줄():
    hwp.HAction.Run("DeleteBack")
    hwp.HAction.Run("MoveSelNextWord")
    hwp.HAction.Run("MoveSelLeft")
    hwp.HAction.Run("CharShapeBold")
    hwp.HAction.Run("CharShapeUnderline")
    hwp.HAction.Run("Cancel")

설명드렸다시피 위의 코드 중

Run("CharShapeBold")와 Run("CharShapeUnderline")에는

크다면 큰 버그가 있는데요.

그건 바로,

토글 방식의 명령어이기 때문에

기존에 진하게&밑줄이 적용되어 있는 경우에

위의 코드를 실행하면

서식이 해제되어버립니다.

한마디로 불안정하죠.

 

그래서 API 문서를 응용해서

아래처럼 더 견고한 방법을 적용해보았습니다.

## 변경 전
def 한글_진하게밑줄():
    hwp.HAction.Run("DeleteBack")
    hwp.HAction.Run("MoveSelNextWord")
    hwp.HAction.Run("MoveSelLeft")
    hwp.HAction.Run("CharShapeBold")
    hwp.HAction.Run("CharShapeUnderline")
    hwp.HAction.Run("Cancel")
    
###################################################################

## 변경 후
def 한글_진하게밑줄():
    hwp.Run("Delete")
    hwp.Run("MoveSelNextWord")
    hwp.Run("MoveSelLeft")
    hwp.XHwpDocuments.Item(0).XHwpCharacterShape.Bold = True
    hwp.XHwpDocuments.Item(0).XHwpCharacterShape.UnderlineType = 1
    hwp.HAction.Run("Cancel")

 

변경한 코드를 적용해서 실행해보겠습니다.

아래의 전체코드가 이해되지 않는다면,
그냥 넘어가지 마시고 꼭 이해하신 후에
다음 포스팅으로 넘어가 주시기 바랍니다.
아직 중요한 설명과, 추가할 코드가 남아 있습니다.

 

전체코드(최종은 아님ㅜ)

import re

import win32com.client as win32


def 한글_진하게밑줄():
    hwp.Run("Delete")
    hwp.Run("MoveSelNextWord")
    hwp.Run("MoveSelLeft")
    hwp.XHwpDocuments.Item(0).XHwpCharacterShape.Bold = True
    hwp.XHwpDocuments.Item(0).XHwpCharacterShape.UnderlineType = 1
    hwp.HAction.Run("Cancel")
    
    
hwp = win32.gencache.EnsureDispatch("hwpframe.hwpobject")  # 한/글 열기
hwp.XHwpWindows.Item(0).Visible = True  # 숨김해제
hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")  # 보안모듈 실행
hwp.Open(r"C:\Users\smj02\Desktop\food_unites_2.hwpx")  # 문서 열기

hwp.InitScan()  # 탐색 초기화
while True:
    상태값, 문자열 = hwp.GetText()
    if 상태값 in (0, 1):  # 문서 끝까지 탐색을 마쳤으면 0 또는 1 리턴
        # 상태값 0 : 텍스트 정보 없음
        # 상태값 1 : 리스트의 끝
        break  # while문 종료
    else:
        hwp.MovePos(201)
        위치리스트 = [m.start() for m in re.finditer("\|", 문자열)]
        for 위치 in 위치리스트:
            hwp.MovePos(1, 0, 위치)  # 해당 인덱스로 캐럿 이동
            한글_진하게밑줄()
            # 본문 수정 후에는 ReleaseScan 후 InitScan을 재시작해야 함
            hwp.ReleaseScan()  # 탐색 종료
            hwp.InitScan(Range=0x0007)  # 탐색 재시작(캐럿 위치~문서의 끝)

 

위의 코드를 한 번 실행해보겠습니다.

아닛, 이게 어떻게 된 거지!?????

아닛!!!!!! 이 버그는 뭔가요????

첫 번째 단락에서 요상한 곳을 막 고치다가

문서를 모조리 망치고 있는데요!??

콘솔에서 재빨리 Ctrl-C를 눌러주세요!ㅜ

 

어떻게 된 거죠?

코드에는 문제가 있는 것 같지 않은데,

어떤 부분이 문제일까요?

 

 

아직 제가 설명드리지 않은 부분이 있습니다.

사실 이 문제를 고치는 건 굉장히 간단한 일이고,

설명도 아주 짧게 가능하지만,

먼저 설명드리면 미리 겁먹고 포기하실까봐

마지막에 알려드립니다ㅜ

GetText를 사용할 때는 첫 단락의 인덱스 수정

항상!!!!! 유념하셔야 하기 때문에

일부러 오류가 발생하는 화면을 먼저 보여드렸습니다.

 

그럼 다음 포스팅에서 이어서 짧게 설명드리겠습니다.

 

GetText의 첫 단락 인덱스를 수정해야 하는 이유

이번 포스팅은 개별 포스팅이 아닙니다. 아래 포스팅의 보충설명입니다. 2022.02.06 - [업무자동화/파이썬-아래아한글 자동화 기초] - GetText 실행 후에 찾아가서 수정하는 방법 GetText 실행 후에 찾아

martinii.fun

 

댓글