안녕하세요?
일상의 코딩, 일코입니다.
지난 포스팅에서는,
문자열을 단락별로 탐색해서 리턴해주는
GetText라는 메서드를 소개해 드렸습니다.
2022.02.04 - [업무자동화/파이썬-아래아한글 자동화 기초] - GetText, 한/글 자동화 고급과정의 첫걸음①
그런데 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를 사용할 때는 첫 단락의 인덱스 수정을
항상!!!!! 유념하셔야 하기 때문에
일부러 오류가 발생하는 화면을 먼저 보여드렸습니다.
그럼 다음 포스팅에서 이어서 짧게 설명드리겠습니다.
'아래아한글 자동화 > python+hwp 중급' 카테고리의 다른 글
GetText의 첫 단락 인덱스를 수정해야 하는 이유(최종) (0) | 2022.02.08 |
---|---|
GetText, 한/글 자동화 고급과정의 첫걸음① (0) | 2022.02.04 |
찾기로 탐색한 단어 말고 바로 뒤의 단어를 조작하고 싶다면? (2) | 2022.02.03 |
댓글