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

[QnA] (4/5) 특정 단어를 포함한 문단 검색하기

by 일코 2022. 9. 19.
안녕하세요.
한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다.

<질문>

특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다.
1. 자동으로 표 생성시 속성을 "본문과의배치"에서 "글뒤로" 선택하여 생성할 수 있나요?
이 속성없이 생성시 문단에 삽입되면서 글자가 밀려나는 현상이 발생합니다.

2. 찾은 문단의 위치값을 HWPUNIT 값으로 알 수 있나요?
표 생성시 위치값은 HWPUNIT으로 지정해야 하는데 현재 찾은 위치의 속성은 줄,칸으로 알려주네요.
이상입니다.

지난 포스팅에서는

지난 포스팅에서는 용지의 너비와 문단의 높이를 구하는 함수를 구현해보았습니다.

2022.09.19 - [업무자동화/파이썬-아래아한글 자동화 응용] - [QnA] (3/5) 문단의 높이와 너비(HwpUnit) 구하기

 

[QnA] (3/?) 문단의 높이(HwpUnit) 구하기

안녕하세요. 한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다. <질문> 특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다. 1. 자

martinii.fun

한/글 API에서는 개체의 XY좌표를 구할 수 없어 막막할 수 있는데,

문단높이는 글자크기와 줄간격, 줄 수를 곱해서 구했고,

문단너비는 용지너비 - 왼쪽여백 - 오른쪽 여백으로 구했습니다.

이처럼 간단한 방법을 여러 가지 활용해서 고급 기능을 구현하는 과정은 항상 흥미롭습니다.

이번 포스팅에서는

이번 시리즈가 다소 길어질 줄 알았는데 벌써 마무리 단계네요.

중간점검차 지금 우리가 작성중인 프로그램을 간략히 설명하면

"특정 단어를 포함한 문단들 뒤에다 1x1의 표를 백그라운드로 삽입해서 테두리를 그린다" 정도로 표현할 수 있겠습니다.

이번 포스팅에서는 특정 단어를 포함한 문단의 좌표(list, para, pos) 중 [0, 1] 인덱스인 list, para 값을 추출해서

파이썬리스트로 수집한 후에 순회하면서 해당 위치로 찾아가는 기능을 구현해보겠습니다.

 

참고) 한/글에서 사용하는 좌표-위치체계

한/글에서 제공하는 위치체계(리스트, 몇 번째 문단인지, 몇 번째 글자인지)에 대해서는 지난 포스팅에서 다룬 적이 있죠.

2022.09.08 - [업무자동화/파이썬-아래아한글 자동화 기초] - 아래아한글 문서의 위치(좌표)체계

 

아래아한글 문서의 위치(좌표)체계

아래아한글 문서의 위치체계 아래아한글 문서에는 명확하게 위치체계가 존재하고, 비어있는 공간이 아닌 이상 좌표(?)가 매겨져 있습니다. 마치 3차원 좌표계(x, y, z)처럼 말이죠. 이 글에서 사용

martinii.fun

그럼 본론으로 들어가보겠습니다.

아래와 같은 문서가 있다고 해봅시다.

예를 들어 "세 줄"이라는 단어를 포함한 문단은 빈 줄을 포함해서 5번째 문단이지요.

찾기(Ctrl-F) 기능을 통해 "세 줄"을 반복해서 탐색해보겠습니다. 아래처럼요.

위 과정을 스크립트매크로로 녹화해보면 다음과 같습니다.

찾기/찾아바꾸기는 다른 포스팅에서도 여러 번 다룬 적이 있습니다.
function OnScriptMacro_script5()
{
	HAction.GetDefault("RepeatFind", HParameterSet.HFindReplace.HSet);
	with (HParameterSet.HFindReplace)
	{
		ReplaceString = "";
		FindString = "세 줄";
		IgnoreReplaceString = 0;
		IgnoreFindString = 0;
		Direction = FindDir("Forward");
		WholeWordOnly = 0;
		UseWildCards = 0;
		SeveralWords = 0;
		AllWordForms = 0;
		MatchCase = 0;
		ReplaceMode = 0;
		ReplaceStyle = "";
		FindStyle = "";
		FindRegExp = 0;
		FindJaso = 0;
		HanjaFromHangul = 0;
		IgnoreMessage = 1;
		FindType = 1;
	}
	HAction.Execute("RepeatFind", HParameterSet.HFindReplace.HSet);
}

불필요한 인자들을 지우고 파이썬 문법으로 바꿔보면,

def 찾기(단어):
    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
    return hwp.HAction.Execute("RepeatFind", hwp.HParameterSet.HFindReplace.HSet)

위 함수는 문서를 한 바퀴 도는 동안 True를 리턴하다가, 모두 찾고 나서 한 바퀴를 다 돌았으면 False를 리턴합니다.

while문으로 찾기 함수를 계속 실행하고,

각 문단 위치를 리스트로 얻은 후, 중복을 제거하면 되겠네요.

문서를 한 바퀴 다 돌면 False를 리턴한다는 점을 while문의 break 조건으로 쓰고요.

문단 위치는 GetPos()로 구하면 됩니다. 간단하네요.

파이썬 코드를 작성해보면

단어 = "세 줄"
문단리스트 = []
while True:
    if 찾기(단어):
        문단리스트.append(hwp.GetPos()[:2])
    else:
        break
문단리스트 = list(set(문단리스트))
print(문단리스트)

위 코드를 실행해보면

(0, 4)라는 튜플 하나만 리턴하네요.

0번 리스트(=본문)의 4번 문단에서만 "세 줄"이라는 단어가 발견되었다는 의미입니다.

위에서 언급했듯이,

간편한 중복제거를 위해 문단 내 글자인덱스인 pos는 빼고 수집했습니다.

(파이썬에서는 list 자료형을 set로 변환하면 중복이 제거됩니다.)

 

다른 검색어로 한 번 더 돌려봅시다.

"세 줄"이 아니라 "줄"이라는 단어를 포함한 리스트를 다시 구해봅니다.

모든 문단이 선택되겠네요.

단어 = "줄"
문단리스트 = []
while True:
    if 찾기(단어):
        문단리스트.append(hwp.GetPos()[:2])
    else:
        break
문단리스트 = sorted(list(set(문단리스트)), reverse=True)
print(문단리스트)

이번에는 리스트를 역순으로 순회하기 위해 sorted(reverse=True) 함수를 적용해보았습니다.

위 코드를 다시 실행해보면

(0, 8), (0, 6), (0, 4), (0, 2), (0, 0) 등 다섯 개의 튜플을 가진 리스트가 생성되었습니다.

각 위치의 시작점으로 이동하려면 pos 파라미터에 0을 추가해야 하는데,

아래처럼 실행하면 되겠습니다.

위치 변수는 길이가 2인 튜플이므로 2개의 인자에 대입하기 위해 언패킹(*)을 했습니다.

 

 

위치 = 문단리스트[0]  # (0, 8)
hwp.SetPos(*위치, 0)
두 번째 라인은 hwp.SetPos(0, 8, 0)과 동일합니다.

 

위 코드를 실행해보면

마지막 퍼즐까지 완성되었네요.

마지막으로 다음 포스팅에서는 이들을 조합해서 최종 프로그램을 짜겠습니다.

2022.09.19 - [업무자동화/파이썬-아래아한글 자동화 응용] - [QnA] (5/5) 특정단어를 포함한 문단을 1x1표로 감싸기-최종

 

[QnA] (5/5) 특정단어를 포함한 문단을 1x1표로 감싸기-최종

안녕하세요. 한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다. <질문> 특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다. 1. 자

martinii.fun

 

댓글