한글 API 에서 찾기, 바꾸기, 블록지정, 블록에 형광펜 적용 기능

동일한 내용의 file 이 2개 있습니다. 하나는 원하는 문구를 찾아 그 문구에 형광펜으로 background color 를 칠하고 싶고 하나는 원하는 문구를 찾아 그 문구를 다른 문구로 변경하고 변경된 문구에 형황펜으로 background color 를 칠하고 싶습니다. 어떻게 하면 되는지 c# 사례를 부탁 드립니다.

2개의 좋아요

안녕하세요 ~ ^^
제가 내부 다른 업무로 샘플 작성까진 어려울것 같습니다. ㅜ
아래와 같은 액션을 이용해주면 될것 같습니다.

RepeatFind - 다시 찾기 액션을 이용해 원하는 단어를 찾아갈수 있습니다.
ReplaceDlg - 찾아바꾸기 액션을 통해 찾은 단어를 다른 단어로 변경 가능합니다.

그리고 MarkPenShape 액션을 통해 형광펜 처리도 가능합니다.

Action 및 ParameterSet 관련 가이드 문서를 보시면 설명이 되어있으니 해당 부분 참고하여 개발하시면 될것같습니다.
감사합니다 ^^

2개의 좋아요

안녕 하세요 ?
제가 3개의 동일한 내용의 아래한글을 가지고 첫번째는 변경하기를 원하는 문구를 변경하고, 두번째는 원본에 변경대상을 형광펜으로 highlight 하고, 세번째는 변경된 문구에 형광펜으로 highlight 하고자 합니다.
그렇게 하기 위해 먼저 세개의 file 이 모두 수정이 되는지 보려고 수정하는 Action(ExecReplace)을 test 하는데 첫번째 file 은 수정이 되지만 두번째와 세번째 file 이 수정이 안되어 아래 code 에서 어디에 문제가 있는지 도움 요청 드립니다. Code 의 기본 가닥은 세개의 file 을 open 하여 배열에 넣고 세번을 각각 실행 하는데 각 file 의 position 을 처음으로 이동후 ExecReplace 를 실행하고 position 을 꺼내 직전 position 과 동일하면 중지하고 다르면 반복하는 것으로 되어 있습니다.

  // 아래한글 file 수정
    private int ChangeHWP(String fileName)
    {
        Boolean cond = false;
        int chgCount = 0;
        Object option = null, range = null, spara = null, spos = null, epara = null, epos = null;

        // HwpObject는 오토메이션 모듈로 “HKEY_Current_User\Software\HNC\HwpAutomation\Modules” 에 보안모듈 등록
        // 값 이름:FilePathCheckerModule, 값 데이터:D:\GitHub\ChangeDocs\FilePathCheckerModuleExample.dll
        cond = hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule");
        HwpObject[] hwpObj = {hwp,hwp,hwp};

        hwpObj[0].Open(@fileName, "", "");
        hwpObj[1].Open(@fileSourceHL, "", "");
        hwpObj[2].Open(@fileOutputHL, "", "");

        try
        {
            // objIdx 는 ppt 변환시 필요에 따라 class 변수로 지정 함
            for (objIdx = 0; objIdx < 3; objIdx++)
            { 
                hwpObj[objIdx].InitScan(option, range, spara, spos, epara, epos);

                var act = hwpObj[objIdx].CreateAction("ExecReplace");
                var pset = act.CreateSet();

                Boolean goNext = true;
                Boolean con = false;
                int[] startPset = new int[3], currPset = new int[3], lastPset = new int[3];

                // 변경기준 수 만큼 반복
                for (int ruleIdx = 0; ruleIdx < dvPhrase.Count; ruleIdx++)
                {
                    // 찾기/바꾸기를 위에서 아래로 하면 처음으로 이동
                    con = hwpObj[objIdx].MovePos(2, 0, 0);
                    // 문서의 뒤에서 부터 찾아/바꾸기 위해 끝으로 이동
                    // con = hwpObj[objIdx].MovePos(3, 0, 0);

                    // Position 이 정상으로 설정되면 처리
                    if (con)
                    {
                        // 설정한 위치를 최근위치에 저장
                        pset = hwpObj[objIdx].GetPosBySet();
                        lastPset[0] = (int)pset.Item("List");
                        lastPset[1] = (int)pset.Item("Para");
                        lastPset[2] = (int)pset.Item("Pos");

                        // Position 을 문서의 끝으로 설정후 backward 방향으로 찾아 바꾸기 반복 실행
                        // 정규식으로 찾기 여부(Java 정규식과 상이하므로 반드시 다음 URL 을 참고하여 정규식을 작성해야 함) 
                        // https://help.hancom.com/hoffice130/ko-KR/Hwp/index.htm#t=edit%2Ffind%2Ffind(options).htm&rhsearch=정규식&rhhlterm=정규식&rhsyns=%20

                        do
                        {
                            hwpObj[objIdx].HAction.GetDefault("ExecReplace", hwpObj[objIdx].HParameterSet.HFindReplace.HSet);

                            hwpObj[objIdx].HParameterSet.HFindReplace.MatchCase = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.AllWordForms = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.SeveralWords = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.UseWildCards = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.WholeWordOnly = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.AutoSpell = 1;
                            hwpObj[objIdx].HParameterSet.HFindReplace.Direction = 0;           // 아랫쪽으로 찾기
                            hwpObj[objIdx].HParameterSet.HFindReplace.IgnoreFindString = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.IgnoreReplaceString = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.FindString = dgPhrase.Rows[ruleIdx].Cells[0].Value.ToString();
                            hwpObj[objIdx].HParameterSet.HFindReplace.ReplaceString = dgPhrase.Rows[ruleIdx].Cells[1].Value.ToString();
                            hwpObj[objIdx].HParameterSet.HFindReplace.ReplaceMode = 1;
                            hwpObj[objIdx].HParameterSet.HFindReplace.IgnoreMessage = 1;
                            hwpObj[objIdx].HParameterSet.HFindReplace.HanjaFromHangul = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.FindJaso = 0;
                            hwpObj[objIdx].HParameterSet.HFindReplace.FindRegExp = 0;          
                            hwpObj[objIdx].HParameterSet.HFindReplace.FindStyle = "";
                            hwpObj[objIdx].HParameterSet.HFindReplace.ReplaceStyle = "";
                            hwpObj[objIdx].HParameterSet.HFindReplace.FindType = 1;

                            hwpObj[objIdx].HAction.Execute("ExecReplace", hwpObj[objIdx].HParameterSet.HFindReplace.HSet);

                            // 원본과 Highlight(수정본) 은 찾은 문자를 변경후 문자로 바꾼다
                            /*
                            if (objIdx == 0 || objIdx == 2)
                            {
                                hwpObj[objIdx].HAction.GetDefault("ReplaceDlg", hwpObj[objIdx].HParameterSet.HFindReplace.HSet);

                                hwpObj[objIdx].HAction.Execute("ReplaceDlg", hwpObj[objIdx].HParameterSet.HFindReplace.HSet);
                            }
                            */
                            // 찾아/바꾸기 후 현재위치 저장
                            pset = hwpObj[objIdx].GetPosBySet();
                            currPset[0] = (int)pset.Item("List");
                            currPset[1] = (int)pset.Item("Para");
                            currPset[2] = (int)pset.Item("Pos");

                            // 현재위치가 최근위치와 동일하면 찾지 못했으므로 count 하지 않고 찾기/바꾸기 중단
                            if (currPset.SequenceEqual(lastPset))
                                goNext = false;
                            else
                                goNext = true;

                                // 현재위치가 처음위치보다 크면 찾아/바꾸기 반복
                                // 찾기/바꾸기를 "위에서 아래로" 또는 "아래서 위로" 하던 관계없이 다음 Method 불필요
                                // goNext = ToProceed(startPset, currPset);

                            // 현재위치가 반복되는지 확인하기 위해 현재위치를 최근위치로 저장
                            lastPset[0] = currPset[0];
                            lastPset[1] = currPset[1];
                            lastPset[2] = currPset[2];

                            // goNext 값이 true 이면 수정 count 증가
                            if (goNext && objIdx == 0) chgCount++;
                        }

                        // goNext 값이 true 이면 찾아/바꾸기 반복
                        while (goNext);
                    }
                }

                // file 이 수정되었으면 저장
                if (chgCount > 0)
                {
                    if (objIdx == 0)
                        // 원본인 경우 수정본 Directory에 저장
                        hwpObj[objIdx].SaveAs(@fileOutput, "", "");
                    else
                        // 변경된 경우 저장
                        hwpObj[objIdx].Save(false);
                }

                // 저장 했으므로 내용을 버린다
                hwpObj[objIdx].Clear(1);
                hwpObj[objIdx].ReleaseScan();
            }
        }
        catch (Exception e)
        {
            txtMessage.AppendText(e.ToString() + "\r\n");
        }

        return chgCount;
    }
2개의 좋아요

안녕하세요, 해당 부분이 조금 이상한것같습니다.
이렇게 정의해도 한글 오토메이션은 하나일것 같은대요
결국 마지막 오픈된 파일만 열러서 API가 동작할것 같습니다.

로직을 돌고난뒤 새로 열고 저장하고 이런식으로 해야하지 않을까요?

2개의 좋아요

조언해 주신 대로 아래와 같이 수정하여 ExecReplace action 을 수행하니 세개의 file 이 동일하게 수정 되었습니다. 다음 단계로 RepeatFind action 으로 변경하여 실행하니 다음과 같이 무한 반복되는 현상이 발생 합니다. ReplaceDlg 를 실행하지 않아서인지 원인을 모르겠습니다.

  1. 처음 시작시 pSet 의 값 : 0,1,0(이 값도 이해가 안됩니다. 왜냐하면 문서의 끝인데 왜 이런 수치가 나오는지 ?)
  2. 찾은곳 pSet 값 : 4,0,1(윗쪽으로 찾기한 위치가 처음 pSet 의 값보다 큼)
  3. 찾은곳 pSet 값 : 4,0,18
  4. 찾은곳 pSet 값 : 4,0,1(여기서 부터 3)번과 4)번을 계속 반복하여 무한 loop 발생

원인이 무엇인지 도움말씀 부탁 드립니다.
그리고 ReplaceDlg action 은 RepeatFind 후 바로 실행하면 찾은 위치는 object 에서 처리 하는지 ? 아니면 Caret 의 위치를 설정해 주어야 하는지요 ?

그리고 MarkPenShape 을 사용할 때 어디선가 보니 시작 위치를 설정하고 MarkPenShape action 을 실행하고 끝나는 위치를 지정해 주어야 하는 것으로 기억 하는데 맞는지요 ?

    // 아래한글 file 수정
    private int ChangeHWP(String fileName)
    {
        Boolean cond = false;
        int chgCount = 0;
        Object option = null, range = null, spara = null, spos = null, epara = null, epos = null;

        // HwpObject는 오토메이션 모듈로 “HKEY_Current_User\Software\HNC\HwpAutomation\Modules” 에 보안모듈 등록
        // 값 이름:FilePathCheckerModule, 값 데이터:D:\GitHub\ChangeDocs\FilePathCheckerModuleExample.dll
        cond = hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule");

        try
        {
            // objIdx 는 ppt 변환시 필요에 따라 class 변수로 지정 함
            for (objIdx = 0; objIdx < 3; objIdx++)
            {

                if (objIdx == 0) hwp.Open(@fileName, "", "");
                if (objIdx == 1) hwp.Open(@fileSourceHL, "", "");
                if (objIdx == 2) hwp.Open(@fileOutputHL, "", "");
                hwp.InitScan(option, range, spara, spos, epara, epos);

                var act = hwp.CreateAction("RepeatFind");
                var pset = act.CreateSet();

                Boolean goNext = true;
                Boolean con = false;
                int[] startPset = new int[3], currPset = new int[3], lastPset = new int[3];

                // 변경기준 수 만큼 반복
                for (int ruleIdx = 0; ruleIdx < dvPhrase.Count; ruleIdx++)
                {
                    // 찾기/바꾸기를 위에서 아래로 하면 처음으로 이동
                    // con = hwp.MovePos(2, 0, 0);
                    // 문서의 뒤에서 부터 찾아/바꾸기 위해 끝으로 이동
                    con = hwp.MovePos(3, 0, 0);

                    // Position 이 정상으로 설정되면 처리
                    if (con)
                    {
                        // 설정한 위치를 최근위치에 저장
                        pset = hwp.GetPosBySet();
                        lastPset[0] = (int)pset.Item("List");
                        lastPset[1] = (int)pset.Item("Para");
                        lastPset[2] = (int)pset.Item("Pos");

                        // Position 을 문서의 끝으로 설정후 backward 방향으로 찾아 바꾸기 반복 실행
                        // 정규식으로 찾기 여부(Java 정규식과 상이하므로 반드시 다음 URL 을 참고하여 정규식을 작성해야 함) 
                        // https://help.hancom.com/hoffice130/ko-KR/Hwp/index.htm#t=edit%2Ffind%2Ffind(options).htm&rhsearch=정규식&rhhlterm=정규식&rhsyns=%20

                        do
                        {
                            hwp.HAction.GetDefault("RepeatFind", hwp.HParameterSet.HFindReplace.HSet);

                            hwp.HParameterSet.HFindReplace.MatchCase = 0;
                            hwp.HParameterSet.HFindReplace.AllWordForms = 0;
                            hwp.HParameterSet.HFindReplace.SeveralWords = 0;
                            hwp.HParameterSet.HFindReplace.UseWildCards = 0;
                            hwp.HParameterSet.HFindReplace.WholeWordOnly = 0;
                            hwp.HParameterSet.HFindReplace.AutoSpell = 1;
                            hwp.HParameterSet.HFindReplace.Direction = 1;           // 윗쪽으로 찾기
                            hwp.HParameterSet.HFindReplace.IgnoreFindString = 0;
                            hwp.HParameterSet.HFindReplace.IgnoreReplaceString = 0;
                            hwp.HParameterSet.HFindReplace.FindString = dgPhrase.Rows[ruleIdx].Cells[0].Value.ToString();
                            hwp.HParameterSet.HFindReplace.ReplaceString = dgPhrase.Rows[ruleIdx].Cells[1].Value.ToString();
                            hwp.HParameterSet.HFindReplace.ReplaceMode = objIdx == 1 ? 0 : 1;
                            hwp.HParameterSet.HFindReplace.IgnoreMessage = 1;
                            hwp.HParameterSet.HFindReplace.HanjaFromHangul = 0;
                            hwp.HParameterSet.HFindReplace.FindJaso = 0;
                            hwp.HParameterSet.HFindReplace.FindRegExp = 0;          
                            hwp.HParameterSet.HFindReplace.FindStyle = "";
                            hwp.HParameterSet.HFindReplace.ReplaceStyle = "";
                            hwp.HParameterSet.HFindReplace.FindType = 1;

                            hwp.HAction.Execute("RepeatFind", hwp.HParameterSet.HFindReplace.HSet);

                            */
                            // 찾아/바꾸기 후 현재위치 저장
                            pset = hwp.GetPosBySet();
                            currPset[0] = (int)pset.Item("List");
                            currPset[1] = (int)pset.Item("Para");
                            currPset[2] = (int)pset.Item("Pos");

                            // 현재위치가 최근위치와 동일하면 찾지 못했으므로 count 하지 않고 찾기/바꾸기 중단
                            if (currPset.SequenceEqual(lastPset))
                                goNext = false;
                            else
                                goNext = true;

                                // 현재위치가 처음위치보다 크면 찾아/바꾸기 반복
                                // 찾기/바꾸기를 "위에서 아래로" 또는 "아래서 위로" 하던 관계없이 다음 Method 불필요
                                // goNext = ToProceed(startPset, currPset);

                            // 현재위치가 반복되는지 확인하기 위해 현재위치를 최근위치로 저장
                            lastPset[0] = currPset[0];
                            lastPset[1] = currPset[1];
                            lastPset[2] = currPset[2];

                            // goNext 값이 true 이면 수정 count 증가
                            if (goNext && objIdx == 0) chgCount++;
                        }

                        // goNext 값이 true 이면 찾아/바꾸기 반복
                        while (goNext);
                    }
                }

                // file 이 수정되었으면 저장
                if (chgCount > 0)
                {
                    if (objIdx == 0)
                        // 원본인 경우 수정본 Directory에 저장
                        hwp.SaveAs(@fileOutput, "", "");
                    else
                        // 변경된 경우 저장
                        hwp.Save(true);
                }

                // 저장 했으므로 내용을 버린다
                hwp.Clear(1);
                hwp.ReleaseScan();
            }
        }
        catch (Exception e)
        {
            txtMessage.AppendText(e.ToString() + "\r\n");
        }

        return chgCount;
    }
2개의 좋아요

안녕하세요, 좌표만 봤을떄
리스트 아이디가 다른걸 봐서 문서가 표로 이루어져있는것 같습니다.

문서의 마지막을 체크하는게 아니라 한번 찾기를 한뒤 그 위치를 기억 해두고 계속 찾기를 반복 한뒤 첫 찾기한 위치가 나오면 멈추면 어떨까 싶습니다.
감사합니다.

2개의 좋아요

현재의 code 가 “ExecReplace” 를 실행하면 정확히 작동 합니다.
그런데 “RepeatFind” 를 실행하니 결과가 달라진다는 것이 이해가 안됩니다.
현재 test 한 원본 file 에는 원하는 문구가 1개 있습니다.
그런데 pSet 값은 2번 바뀝니다.
조언해 주신 내용대로 처리해도 세번째에 더이상 원하는 문구가 없다는 것이 판별되어 뭔가 잘못 처리될 것 같습니다.

아래한글 프로그램에서는 원하는 문구를 찾았는지, 못찾았는지 어떻게 판단을 하는지 그 내용을 알고 싶습니다.
제가 test 를 통해 확인을 해 보니 문구를 찾지 못하면 pSet 값이 변하지 않았습니다.
그런데 찾았는지 못찾았는지 return 되는 값이 없는지요 ?

그리고 ReplaceDlg action 은 다음과 같이 하면 되는지요 ?

GetDefault(“ReplaceDlg”, …);
ReplaceString = “원하는 문구”;
Execute(“ReplaceDlg”, …);

그리고 MarkPenShape 을 사용할 때 다음과 같이 하면 되는지요 ?
GetDefault(“MarkPenShape”, …);
Color = 원하는 color 16진수 값;
Execute(“MarkPenShape”, …);

2개의 좋아요

내부에선 내부 모델에 대해 처리하는 모듈이 있어 해당 부분으로 판단을 하고있습니다

현재 API 구조로는 user81님이 원하시는대로 찾았는지 못찾았는지에 대한 리턴값은 따로 알수가 없네요 ㅠ

바꿀문자열은 ReplaceString 넣어주시면 되고
마크펜도 Colorref 값에 맞게 Color Set에 넣어주시면 됩니다.
감사합니다.

2개의 좋아요

아래와 같이 code 보완하여 찾은 문구에 형광펜 칠하는 것 까지 작동이 됩니다.
그런데 문구를 수정하는 기능인 “ReplaceDlg” action 이 안되는데 도움 부탁 드립니다.

그리고 현재 찾는 부분이 실제 문구가 있는 숫자보다 +1 많게 count 됩니다.
그래서 처음에 구현했던 “ExecReplace” action 을 다시 쓰려고 하는데 수정을 원할 경우 “ReplaceMode” 를 1로 하고 찾기만 할 경우 0 로 하면 되는지요 ?

또 GetDefault 를 실행한후 parameter 값을 모두 설정해야 하는지 아니면 default 값을 바꿀 경우에만 설정하면 되는지 궁금 합니다.

    // 아래한글 file 수정
    private int ChangeHWP(String fileName)
    {
        Boolean cond = false;
        int chgCount = 0;
        Object option = null, range = null, spara = null, spos = null, epara = null, epos = null;

        // HwpObject는 오토메이션 모듈로 “HKEY_Current_User\Software\HNC\HwpAutomation\Modules” 에 보안모듈 등록
        // 값 이름:FilePathCheckerModule, 값 데이터:D:\GitHub\ChangeDocs\FilePathCheckerModuleExample.dll
        cond = hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule");

        try
        {
            // objIdx 는 ppt 변환시 필요에 따라 class 변수로 지정 함
            for (objIdx = 0; objIdx < 3; objIdx++)
            {

                if (objIdx == 0) hwp.Open(@fileName, "", "");
                if (objIdx == 1) hwp.Open(@fileSourceHL, "", "");
                if (objIdx == 2) hwp.Open(@fileOutputHL, "", "");
                hwp.InitScan(option, range, spara, spos, epara, epos);

                var act = hwp.CreateAction("RepeatFind");
                var pset = act.CreateSet();

                // 변경기준 수 만큼 반복
                for (int ruleIdx = 0; ruleIdx < dvPhrase.Count; ruleIdx++)
                {
                    Boolean goNext = true;
                    Boolean con = false;
                    int[] startPset = new int[3], currPset = new int[3], lastPset = new int[3];

                    // 찾기/바꾸기를 위에서 아래로 하면 처음으로 이동
                    con = hwp.MovePos(2, 0, 0);
                    // 문서의 뒤에서 부터 찾아/바꾸기 위해 끝으로 이동
                    // con = hwp.MovePos(3, 0, 0);

                    // Position 이 정상으로 설정되면 처리
                    if (con)
                    {
                        // 설정한 위치를 최근위치에 저장
                        pset = hwp.GetPosBySet();
                        lastPset[0] = (int)pset.Item("List");
                        lastPset[1] = (int)pset.Item("Para");
                        lastPset[2] = (int)pset.Item("Pos");

                        // Position 을 문서의 끝으로 설정후 backward 방향으로 찾아 바꾸기 반복 실행
                        // 정규식으로 찾기 여부(Java 정규식과 상이하므로 반드시 다음 URL 을 참고하여 정규식을 작성해야 함) 
                        // https://help.hancom.com/hoffice130/ko-KR/Hwp/index.htm#t=edit%2Ffind%2Ffind(options).htm&rhsearch=정규식&rhhlterm=정규식&rhsyns=%20

                        do
                        {
                            hwp.HAction.GetDefault("RepeatFind", hwp.HParameterSet.HFindReplace.HSet);

                            hwp.HParameterSet.HFindReplace.MatchCase = 0;
                            hwp.HParameterSet.HFindReplace.AllWordForms = 0;
                            hwp.HParameterSet.HFindReplace.SeveralWords = 0;
                            hwp.HParameterSet.HFindReplace.UseWildCards = 0;
                            hwp.HParameterSet.HFindReplace.WholeWordOnly = 0;
                            hwp.HParameterSet.HFindReplace.AutoSpell = 1;
                            hwp.HParameterSet.HFindReplace.Direction = 0;
                            hwp.HParameterSet.HFindReplace.IgnoreFindString = 0;
                            hwp.HParameterSet.HFindReplace.IgnoreReplaceString = 0;
                            hwp.HParameterSet.HFindReplace.FindString = dgPhrase.Rows[ruleIdx].Cells[0].Value.ToString();
                            hwp.HParameterSet.HFindReplace.ReplaceString = dgPhrase.Rows[ruleIdx].Cells[1].Value.ToString();
                            hwp.HParameterSet.HFindReplace.ReplaceMode = 0;
                            hwp.HParameterSet.HFindReplace.IgnoreMessage = 1;
                            hwp.HParameterSet.HFindReplace.HanjaFromHangul = 0;
                            hwp.HParameterSet.HFindReplace.FindJaso = 0;
                            hwp.HParameterSet.HFindReplace.FindRegExp = 0;          
                            hwp.HParameterSet.HFindReplace.FindStyle = "";
                            hwp.HParameterSet.HFindReplace.ReplaceStyle = "";
                            hwp.HParameterSet.HFindReplace.FindType = 1;

                            hwp.HAction.Execute("RepeatFind", hwp.HParameterSet.HFindReplace.HSet);

                            // 찾아/바꾸기 후 현재위치 저장
                            pset = hwp.GetPosBySet();
                            currPset[0] = (int)pset.Item("List");
                            currPset[1] = (int)pset.Item("Para");
                            currPset[2] = (int)pset.Item("Pos");

                            // 현재위치가 최근위치와 동일하면 찾지 못했으므로 count 하지 않고 찾기/바꾸기 중단
                            if (startPset.SequenceEqual(currPset) || currPset.SequenceEqual(lastPset))
                                goNext = false;
                            else
                            {
                                if (startPset[0] == 0 && startPset[1] == 0 && startPset[2] == 0)
                                {
                                    startPset[0] = currPset[0];
                                    startPset[1] = currPset[1];
                                    startPset[2] = currPset[2];
                                }

                                if (objIdx != 1)
                                {
                                    // 찾은 내용을 변경후 문구로 바꾼다
                                    hwp.HAction.GetDefault("ReplaceDlg", hwp.HParameterSet.HFindReplace.HSet);

                                    hwp.HParameterSet.HFindReplace.MatchCase = 0;
                                    hwp.HParameterSet.HFindReplace.AllWordForms = 0;
                                    hwp.HParameterSet.HFindReplace.SeveralWords = 0;
                                    hwp.HParameterSet.HFindReplace.UseWildCards = 0;
                                    hwp.HParameterSet.HFindReplace.WholeWordOnly = 0;
                                    hwp.HParameterSet.HFindReplace.AutoSpell = 1;
                                    hwp.HParameterSet.HFindReplace.Direction = 0;
                                    hwp.HParameterSet.HFindReplace.IgnoreFindString = 0;
                                    hwp.HParameterSet.HFindReplace.IgnoreReplaceString = 0;
                                    hwp.HParameterSet.HFindReplace.FindString = dgPhrase.Rows[ruleIdx].Cells[0].Value.ToString();
                                    hwp.HParameterSet.HFindReplace.ReplaceString = dgPhrase.Rows[ruleIdx].Cells[1].Value.ToString();
                                    hwp.HParameterSet.HFindReplace.ReplaceMode = 1;
                                    hwp.HParameterSet.HFindReplace.IgnoreMessage = 1;
                                    hwp.HParameterSet.HFindReplace.HanjaFromHangul = 0;
                                    hwp.HParameterSet.HFindReplace.FindJaso = 0;
                                    hwp.HParameterSet.HFindReplace.FindRegExp = 0;
                                    hwp.HParameterSet.HFindReplace.FindStyle = "";
                                    hwp.HParameterSet.HFindReplace.ReplaceStyle = "";
                                    hwp.HParameterSet.HFindReplace.FindType = 1;

                                    hwp.HAction.Execute("ReplaceDlg", hwp.HParameterSet.HFindReplace.HSet);
                                }

                                if (objIdx > 0)
                                {
                                    hwp.HAction.GetDefault("MarkPenShape", hwp.HParameterSet.HMarkPenShape.HSet);

                                    hwp.HParameterSet.HMarkPenShape.Color = Convert.ToInt32(
                                        $"{int.Parse(dtColor.Rows[projectRowIndex].ItemArray[3].ToString()):X}" +
                                        $"{int.Parse(dtColor.Rows[projectRowIndex].ItemArray[2].ToString()):X}" +
                                        $"{int.Parse(dtColor.Rows[projectRowIndex].ItemArray[1].ToString()):X}", 16);

                                    hwp.HAction.Execute("MarkPenShape", hwp.HParameterSet.HMarkPenShape.HSet);
                                    /*
                                        // Highlight 본에 찾은 문자열의 배경색을 칠한다
                                        hwp.HAction.GetDefault("CharShape", hwp.HParameterSet.HCharShape.HSet);

                                        hwp.HParameterSet.HCharShape.Color = 0x0080ff80;

                                        Convert.ToInt32(
                                        $"{int.Parse(dtColor.Rows[0].ItemArray[1].ToString()):X}" +
                                        $"{int.Parse(dtColor.Rows[0].ItemArray[2].ToString()):X}" +
                                        $"{int.Parse(dtColor.Rows[0].ItemArray[3].ToString()):X}", 16);

                                        hwp.HAction.Execute("CharShape", hwp.HParameterSet.HFindReplace.HSet);
                                    */
                                }

                                goNext = true;
                            }

                            // 현재위치가 처음위치보다 크면 찾아/바꾸기 반복
                            // 찾기/바꾸기를 "위에서 아래로" 또는 "아래서 위로" 하던 관계없이 다음 Method 불필요
                            // goNext = ToProceed(startPset, currPset);

                            // 현재위치가 반복되는지 확인하기 위해 현재위치를 최근위치로 저장
                            lastPset[0] = currPset[0];
                            lastPset[1] = currPset[1];
                            lastPset[2] = currPset[2];

                            // goNext 값이 true 이면 수정 count 증가
                            if (goNext && objIdx == 0) chgCount++;
                        }

                        // goNext 값이 true 이면 찾아/바꾸기 반복
                        while (goNext);
                    }
                }

                // file 이 수정되었으면 저장
                if (chgCount > 0)
                {
                    if (objIdx == 0)
                        // 원본인 경우 수정본 Directory에 저장
                        hwp.SaveAs(@fileOutput, "", "");
                    else
                        // 변경된 경우 저장
                        hwp.Save(true);
                }

                // 저장 했으므로 내용을 버린다
                hwp.Clear(1);
                hwp.ReleaseScan();
            }
        }
        catch (Exception e)
        {
            txtMessage.AppendText(e.ToString() + "\r\n");
        }

        return chgCount;
    }
2개의 좋아요

찾아바꾸기는 ReplaceDlg 말고,
ExecReplaceAllReplace 등의 액션아이디를 사용하시면 됩니다.
(파이썬 코드지만) 모두 찾아바꾸기 함수의 예시를 보여드리면

def all_replace(src: str, dst: str) -> bool:
    pset = hwp.HParameterSet.HFindReplace
    hwp.HAction.GetDefault("AllReplace", pset.HSet)
    pset.Direction = hwp.FindDir("AllDoc")
    pset.FindString = src
    pset.ReplaceString = dst
    pset.ReplaceMode = 1
    pset.IgnoreMessage = 1
    pset.FindType = 1
    return hwp.HAction.Execute("AllReplace", pset.HSet)

이런 식으로 짜시면 됩니다.

녹화_2023_12_20_16_17_42_401

1개의 좋아요

참고로,
특정 문자열을 찾은 후 뭔가 변경해야 한다든지,
서식을 적용해야 한다든지 그런 경우에는
개인적으로는

  1. 바꿀 문자열 좌표를 먼저 전부 수집한 후 / 끝에서부터 역순으로 수정을 하거나
  2. 바꿀 문자열 갯수를 먼저 센 후 / for문으로 반복작업을 합니다.

수정작업 없이 "찾기"만 실행하면, 한 바퀴 도는 시점이 되었을 때
Execute가 False를 리턴하기 때문에 while문으로 반복하기가 참 간편한데
뭔가 수정작업이 들어가면 그게 안 되더라고요.

아래는 문자열 찾아서 형광펜 칠하는 코드 예시입니다.
이런 프로세스로 작업하시면 코드가 간결해질 것 같네요.

녹화_2023_12_20_16_50_34_341

1개의 좋아요

변경을 원하는 문구가 몇개나 발견이 되는지, 발견되는 곳은 어디인지를 인지하면서 처리하고 싶은데 잘 안되네요. 댓글 감사 합니다.

2개의 좋아요

①갯수를 세려면 find를 쓰시는 방법도 있고요. (한바퀴 돌면 False를 리턴하니까 while문으로)
녹화_2023_12_22_20_49_54_11

② 아니면 그냥 GetTextFile 같은 메서드로 전체 텍스트를 추출해서 count 같은 함수를 쓰시면 편해요. 이전 댓글의 움짤에서도 hwp.GetTextFile()이 리턴한 문서 전체 문자열에서 count 메서드를 실행했거든요.

③ 매번 찾은 구간의 위치를 담고 싶으시면 찾기 실행마다 GetSelectedPos를 실행해서 (slist, spara, spos, elist, epara, epos)를 임의의 배열에 담으시면 될 것 같아요. (매번 특정단어를 찾았을 때마다 선택된 상태니까요.)

녹화_2023_12_22_20_47_07_567

많은 참고가 되어 감사 합니다. GetPosBySet 으로 위치를 저장하면 효율적 처리가 가능할 것 같습니다. 왜냐하면 현재 동일한 내용의 file 4개를 다루는데 1번은 원본, 2번은 원본에 수정을 원하는 문구 Highlight, 3번은 원하는 문구를 수정후 수정한 문구에 Highlight, 4번은 1번을 수정한 수정본 저장을 합니다. 그런데 원하는 위치와 길이를 저장하면 2, 3, 4번 file 을 처리할 때 찾는 시간을 줄일수 있지 않을까 생각 됩니다. 그리고 바꾸기와 Highlight 기능을 쉽게 할수 있을것 같습니다.

2개의 좋아요

현재 구현하려는 기능은 다음과 같은데 3)번 file 에 수정이 안되고 Highlight 만 됩니다. Debugging 을 해 보니 첫번째 원하는 문구를 ExecReplace 를 통해 찾으면 바로 수정이 안되고 그다음 MarkPenShape 이 실행되어 Highlight 만 된 결과가 됩니다. 그래서 MarkPenShape 을 제외하니 첫번째 문구를 찾고 두번째 문구를 찾을때 Execute 를 하면 그때 첫번째 문구가 수정되고 동시에 두번째 문구가 선택이 되어 정상적으로 수정이 됩니다. 이 동작을 원하는 문구를 찾아 바로 수정되고 그다음 MarkPenShape 가 실행되게 할 수 없는지요 ?

  1. 원본 file
  2. 원본 file 의 수정을 원하는 문구에 Highlight
  3. 원본 file 의 수정을 원하는 문구를 수정하고 수정된 문구에 Highlight
  4. 원본 file 의 수정을 원하는 문구를 수정하고 저장

현재는 3)번 file 을 2단계로 나누어 해결은 했습니다.
첫번째는 찾아서 Highlight 반복한 후 저장, 두번째 동일한 file 을 열어 수정하는 방법을 쓰는데 동일한 file 을 두번 처리를 해야 하는 부분이 마음에 들지 않습니다.

2개의 좋아요

"찾아바꾸기 실행시 형광펜 색칠도 하고 싶다"라는 말씀으로 이해되는데요.

ExecReplace 액션은 작동방식이 약간 다르게 정의되어 있습니다.

  1. 먼저 find 실행, (찾은 문구 선택상태)
  2. 선택한 텍스트를 바꾸고, 다음으로 찾은 텍스트 선택
    녹화_2023_12_25_22_04_27_324

이렇게 두 단계입니다.
(다소 직관적이지 않을 수 있겠습니다.)
그래서 교체와 동시에 별도의 액션(형광펜 등)을 추가하셔야 한다면
ExecReplace 대신 Find를 사용하셔야 하며,
바꾸기 및 기타 동작을 Find 액션 바깥에 임의로 추가하셔야 합니다.

아마 충분히 고민해 보셨을 것으로 생각되고, (이미 해결하셨겠지만)
개인적으로 그나마 가장 간편하게 처리하는 방법은, "임시 누름틀 활용"입니다.

  1. 특정 문자열 찾기 이후 해당 영역에 임시로 “누름틀 생성” (반복)
  2. 만들어진 누름틀마다 필드텍스트 교체 및 형광펜 실행 (반복)

이렇게 두 번의 for문으로 교체하는 방식이 그나마 직관적인 것 같습니다.
녹화_2023_12_26_00_12_14_127

코드는 대략 아래와 같습니다.
(임의로 함수를 만들어 처리했지만, 프로세스 자체는 이해하실 것으로 생각합니다.)

# 대상 지정
target_word = "hello"
word_count = hwp.count(target_word)

# 모든 대상에 임시필드 생성
for i in range(word_count):
    hwp.find(target_word, direction="Backward")
    hwp.create_field(name=target_word)

# 대상 문자열 교체
hwp.put_field_text(target_word, "hi")

# 모든 대상에 형광펜 적용
for i in range(word_count):
    hwp.move_to_field(f"{target_word}{{{{{i}}}}}", select=True)
    hwp.markpen_on_selection()

# 임시 필드 삭제
hwp.delete_field_by_name(target_word)

더 좋은 방법을 찾으시면 공유 부탁드립니다. 감사합니다^^

1개의 좋아요