엑셀 매크로 B-XLAM

엑셀에서 한글·PDF·폴더·표 정리를 한 번에

← 엑셀 매크로 페이지로 · 내려받기

13.VBA 소스 — 복사·다운로드·소스 분석(심화)

BX-v7.xlam 에 든 VBA 소스 48개 모듈(15,337줄)을 리본 기능별로 묶었습니다. 내려받은 xlam 의 VBA 편집기(Alt+F11)에서 보는 코드와 같습니다.

방법 1 · 코드 복사해서 붙여넣기

  1. 모듈의 [코드 복사]를 누릅니다.
  2. Excel 에서 Alt+F11 → [삽입] → [모듈](clsXXX 는 [클래스 모듈])을 만들고, 속성 창(F4)의 (이름)을 모듈 이름(예: modMain)으로 바꾼 뒤 붙여 넣습니다(Ctrl+V).

방법 2 · .bas / .cls 파일 가져오기

  1. [.bas 다운로드](클래스는 .cls)로 받습니다. 모두 받으려면 전체 소스 zip(188 KB).
  2. VBA 편집기 [파일] → [파일 가져오기](Ctrl+M)에서 고릅니다. 파일은 VBA 편집기 내보내기 형식(Attribute VB_Name 포함, CRLF 줄바꿈, CP949 인코딩)이라 가져오면 모듈 이름과 한글이 그대로 살아 있습니다. 메모장 등에서 UTF-8 로 다시 저장하면 한글이 깨지니 받은 파일을 그대로 가져오세요.

대부분의 기능은 공통 모듈(modUtil · modRibbonUI · modUITheme · frmChoice …)을 함께 부르므로 한 모듈만 가져오면 '정의되지 않았습니다' 오류가 날 수 있습니다. 폼(frmChoice · frmInput)은 화면 배치가 xlam 안 .frx 에 있어 코드만 제공하고, 리본 버튼도 xlam 안 XML 에 있습니다. 바로 쓰실 때는 완성본 BX-v7.xlam 을, 공부·수정용으로는 이 소스를 쓰세요.

심화과정 — 기능마다 [심화과정: 소스 분석]을 펼치면 리본 버튼에서 시작하는 호출 흐름, 핵심 VBA 객체, 고쳐 쓰는 방법이 나옵니다. 줄 번호를 누르면 해당 모듈 소스의 그 줄로 이동합니다.

01UBIS예산확인 UBIS

세출예산요구서·102-B 장표·팀원 명단을 불러와 예산보드(팀·세부사업·사업명 슬라이서)·세부산출내역·담당자별 집행 현황 대시보드를 만듭니다. 슬라이서로 팀을 고르면 빈 행은 자동으로 숨습니다(clsBoardEvents).

모듈 12개 · 3,429줄 · 리본 버튼 → 진입 프로시저 UB_새보드 (modMain)

modMain 표준 모듈 · 171줄

리본 진입점(UB_Ribbon → UB_Run)과 태그별 기능 분기, 보드 통합문서 확보(EnsureBoard)·설치, 전체 새로고침 순서(새로고침)를 담당하는 오케스트레이션 모듈입니다.

소스 보기 (171줄)
modImport 표준 모듈 · 238줄

세출예산요구서와 장표(102-A/102-B) 파일을 읽기 전용으로 열어 숨김 원본 시트로 값만 복사합니다. 머리글로 장표 종류를 판별하고 예산소관부서명으로 우리 부서 행만 걸러 냅니다.

소스 보기 (238줄)
modStaffImport 표준 모듈 · 227줄

부서명단 파일(xlsx·docx·hwpx·hwp)에서 성명·팀·직위 열을 찾아 부서담당자 시트 5행부터 기록합니다. hwpx 는 압축을 풀어 정규식으로 표를 읽고, hwp 는 한글 자동화로 hwpx 로 바꾼 뒤 같은 경로로 읽습니다.

소스 보기 (227줄)
modMapping 표준 모듈 · 321줄

부서담당자·단위사업카드 시트를 만들고, 사용자가 노란 칸에 입력한 담당자·과제카드·장표 직접지정 값을 키 기준으로 읽어 모델에 덮어씁니다(ReadCardOverrides, ReadStaffTeams).

소스 보기 (321줄)
modModel 표준 모듈 · 364줄

요구서(사업항목 1레벨)와 장표(세목 말단행 합산)를 '세부사업|사업항목' 정규화 키로 매칭해 gItems 모델을 만듭니다. 실집행액 계산, 담당자→팀 배정, 장표 순서 정렬도 여기서 합니다.

소스 보기 (364줄)
modCalc 표준 모듈 · 265줄

요구서의 산출기초 행을 그대로 펼친 세부산출내역 표를 만들고, 메모 열을 키 기준으로 보존하며 산출내역·메모 키워드 찾기(자동 필터)와 슬라이서를 붙입니다.

소스 보기 (265줄)
modBoard 표준 모듈 · 232줄

메인 시트의 도형 버튼 배치(SetupMainSheet)와 사업항목별 집행 표·KPI·슬라이서(BuildMain), 인쇄, 상태 글자색 지정을 담당합니다.

소스 보기 (232줄)
modChart 표준 모듈 · 651줄

숨김 '차트자료' 시트에 세목 단위 원본 표와 팀·세목·사업 TOP·담당자 집계 수식 블록을 만들고, 예산보드 시트에 KPI 카드와 격자 표를 수식 참조로 그려 슬라이서와 연동합니다.

소스 보기 (651줄)
modDetail 표준 모듈 · 215줄

장표를 사업항목→세출세목으로 집계(ItemSubtotals)해 '사업총액' 행과 '세목' 행을 번갈아 놓은 세부현황 표를 만듭니다. 이 집계 함수는 예산보드에서도 함께 씁니다.

소스 보기 (215줄)
modUtil 표준 모듈 · 659줄

여러 모듈이 함께 쓰는 공통 유틸리티 모듈입니다. 시트 이름 상수, 보드 통합문서 찾기(BW), 머리글 탐색(FindHeaderRow·HeaderMap·HCol), 문자열 정규화(CleanText·NormKey·MakeKey), 설정 시트 읽기/쓰기(CfgGet·CfgSet), 버튼·표·슬라이서·KPI 카드 생성, 속도 모드(SpeedOn·SpeedOff), 색상 함수를 제공합니다.

소스 보기 (659줄)
clsProject 클래스 모듈 · 46줄

사업항목 1건을 담는 데이터 클래스입니다. 요구액·예산현액·집행액 등 필드와, 잔액·집행률·상태·담당자(수정값 우선)를 계산해 돌려주는 Property Get 을 가집니다.

소스 보기 (46줄)
clsBoardEvents 클래스 모듈 · 40줄

WithEvents 로 Application 의 SheetCalculate 이벤트를 받아, 이름이 BX_HIDE_ 로 시작하는 범위에서 값이 빈 행을 자동으로 숨깁니다(슬라이서 선택 → 재계산 → 빈 줄 숨김).

소스 보기 (40줄)
심화과정: 소스 분석

리본 버튼("UBIS예산확인")의 태그를 UB_Run 이 받아 보드 통합문서를 확보한 뒤, 기관 예산시스템에서 내려받은 세출예산요구서와 집행 장표(102-A/102-B)를 숨김 원본 시트로 값만 복사합니다. 새로고침 때마다 두 원본을 Scripting.Dictionary 기반 모델(gItems, 항목 = clsProject)로 합치고, 그 모델로 메인 보드·세부현황·예산보드·세부산출내역 시트를 엑셀 표(ListObject)와 슬라이서, SUBTOTAL 수식으로 다시 그립니다. 슬라이서로 필터하면 '보이는 행만' 합산하는 수식 덕분에 KPI와 표가 즉시 따라 바뀝니다.

모듈 구성

  • modMain — 리본 진입점(UB_Ribbon → UB_Run)과 태그별 기능 분기, 보드 통합문서 확보(EnsureBoard)·설치, 전체 새로고침 순서(새로고침)를 담당하는 오케스트레이션 모듈입니다.
  • modImport — 세출예산요구서와 장표(102-A/102-B) 파일을 읽기 전용으로 열어 숨김 원본 시트로 값만 복사합니다. 머리글로 장표 종류를 판별하고 예산소관부서명으로 우리 부서 행만 걸러 냅니다.
  • modStaffImport — 부서명단 파일(xlsx·docx·hwpx·hwp)에서 성명·팀·직위 열을 찾아 부서담당자 시트 5행부터 기록합니다. hwpx 는 압축을 풀어 정규식으로 표를 읽고, hwp 는 한글 자동화로 hwpx 로 바꾼 뒤 같은 경로로 읽습니다.
  • modMapping — 부서담당자·단위사업카드 시트를 만들고, 사용자가 노란 칸에 입력한 담당자·과제카드·장표 직접지정 값을 키 기준으로 읽어 모델에 덮어씁니다(ReadCardOverrides, ReadStaffTeams).
  • modModel — 요구서(사업항목 1레벨)와 장표(세목 말단행 합산)를 '세부사업|사업항목' 정규화 키로 매칭해 gItems 모델을 만듭니다. 실집행액 계산, 담당자→팀 배정, 장표 순서 정렬도 여기서 합니다.
  • modCalc — 요구서의 산출기초 행을 그대로 펼친 세부산출내역 표를 만들고, 메모 열을 키 기준으로 보존하며 산출내역·메모 키워드 찾기(자동 필터)와 슬라이서를 붙입니다.
  • modBoard — 메인 시트의 도형 버튼 배치(SetupMainSheet)와 사업항목별 집행 표·KPI·슬라이서(BuildMain), 인쇄, 상태 글자색 지정을 담당합니다.
  • modChart — 숨김 '차트자료' 시트에 세목 단위 원본 표와 팀·세목·사업 TOP·담당자 집계 수식 블록을 만들고, 예산보드 시트에 KPI 카드와 격자 표를 수식 참조로 그려 슬라이서와 연동합니다.
  • modDetail — 장표를 사업항목→세출세목으로 집계(ItemSubtotals)해 '사업총액' 행과 '세목' 행을 번갈아 놓은 세부현황 표를 만듭니다. 이 집계 함수는 예산보드에서도 함께 씁니다.
  • modUtil — 여러 모듈이 함께 쓰는 공통 유틸리티 모듈입니다. 시트 이름 상수, 보드 통합문서 찾기(BW), 머리글 탐색(FindHeaderRow·HeaderMap·HCol), 문자열 정규화(CleanText·NormKey·MakeKey), 설정 시트 읽기/쓰기(CfgGet·CfgSet), 버튼·표·슬라이서·KPI 카드 생성, 속도 모드(SpeedOn·SpeedOff), 색상 함수를 제공합니다.
  • clsProject — 사업항목 1건을 담는 데이터 클래스입니다. 요구액·예산현액·집행액 등 필드와, 잔액·집행률·상태·담당자(수정값 우선)를 계산해 돌려주는 Property Get 을 가집니다.
  • clsBoardEvents — WithEvents 로 Application 의 SheetCalculate 이벤트를 받아, 이름이 BX_HIDE_ 로 시작하는 범위에서 값이 빈 행을 자동으로 숨깁니다(슬라이서 선택 → 재계산 → 빈 줄 숨김).

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modMain 39~72줄(UB_Ribbon, UB_Run)① 리본 태그로 기능 분기리본 버튼의 콜백 UB_Ribbon 은 control.tag 문자열만 UB_Run 에 넘깁니다. UB_Run 은 먼저 EnsureBoard 로 보드 통합문서를 확보하고, 태그가 UB_새보드 이면 새 통합문서를 만들어 설치만 하고 끝냅니다. 그 밖의 태그는 Select Case 로 요구서선택·장표선택·새로고침버튼·예산보드 등 같은 이름의 프로시저를 호출하며, 오류는 EH 레이블에서 메시지 상자로 알려 줍니다.
  2. modMain 75~88줄(EnsureBoard)② 보드 통합문서 확보와 설치추가 기능(ThisWorkbook.IsAddin)으로 실행 중이면 활성 통합문서에 '메인' 또는 '설정' 시트가 있는지 IsBoardWB(modUtil)로 확인하고, 없으면 Workbooks.Add 로 새 통합문서를 만들어 설치(9-19줄)를 부릅니다. 설치는 CfgSheet 로 숨김 설정 시트를, modBoard 의 SetupMainSheet 로 ①~③·인쇄·예산보드 등 도형 버튼을 만들고 빈 기본 시트를 지웁니다. 이후 모든 모듈은 modUtil 의 BW() 로 이 보드 통합문서를 참조합니다.
  3. modImport 39~96줄(장표선택)③ 장표 가져오기와 부서 필터GetOpenFilename 의 다중 선택으로 장표 파일들을 받아 Workbooks.Open(ReadOnly:=True, UpdateLinks:=0) 으로 엽니다. '회계연도' 머리글 행을 찾아 사업항목명1 열이 있으면 102-B, 사업항목1레벨 이 있으면 102-A 로 판별하고, 부서명이 없으면 PickDept 로 부서 목록을 보여 고르게 합니다. CopyValues(109-148줄)는 UsedRange 를 배열로 읽어 예산소관부서명에 부서명이 포함된 행과 머리글 위쪽 행만 원본 시트에 한 번에 씁니다. 요구서선택(7-36줄)도 같은 방식으로 요구서를 복사하고 '부서)명 :' 뒤 글자를 부서명으로 저장합니다.
  4. modStaffImport 147~198줄(ReadHwpxRows, ParseHwpxTables)④ 부서명단 파일 읽기(선택 기능)부서명단파일선택은 확장자별로 읽기 함수를 고릅니다. hwpx 는 파일을 src.zip 으로 복사한 뒤 Shell.Application 의 CopyHere 로 임시 폴더에 풀고, Contents 폴더의 section*.xml 을 ADODB.Stream(UTF-8)으로 읽습니다. ParseHwpxTables 는 VBScript.RegExp 로 hp:tr → hp:tc → hp:t 순서로 행·셀·글자를 뽑아 행 배열 Collection 을 만듭니다. WriteStaffRows(38-93줄)가 머리글에서 성명·팀·직위 열을 찾아 부서담당자 시트에 기록하고 [적용] 여부를 묻습니다.
  5. modMain 98~129줄(새로고침)⑤ 전체 새로고침 순서원본 시트가 하나도 없으면 안내 후 끝내고, gAutoBusy 플래그로 중복 실행을 막은 뒤 SpeedOn 으로 화면 갱신·계산을 끕니다. 단계마다 gStep 에 이름을 넣고 CleanupLegacySheets → BuildModel → (있으면) RefreshStaffSheet·RefreshCardSheet(modMapping) → BuildMain → BuildGrouped → BuildChartBoard → BuildCalc 순서로 호출합니다. 오류가 나면 EH 에서 gStep 을 함께 보여 주므로 어느 단계에서 실패했는지 바로 알 수 있습니다.
  6. modModel 209~258줄(MatchAll)⑥ 요구서와 장표 매칭으로 모델 구성BuildModel(15-31줄)은 ParseRequest 로 요구서의 '1. 사업명' 행을 clsProject 로 만들고(금액은 천원 단위라 * 1000), AggregateFromSheet 로 세목코드가 있는 장표 말단행을 같은 키로 합산합니다. MatchAll 은 요구서 항목마다 장표 키를 '직접지정 → 완전일치 → 같은 세부사업 안 포함관계(가장 긴 이름)' 순으로 찾고, 장표 순서를 기준으로 새 gItems 를 만들어 요구서의 담당자·요구액을 붙입니다. 장표가 없으면 요구액을 예산현액으로 대신 쓰며, 마지막에 ApplyOverride 와 AssignTeams 로 사용자 수정값과 팀을 반영합니다.
  7. modBoard 64~187줄(BuildMain)⑦ 메인 보드 표·KPI·슬라이서ClearRowsKeepTables 로 표 머리글과 슬라이서는 남긴 채 5행 아래를 비우고, SortedKeys 순서로 clsProject 의 예산현액·집행액·잔액·집행률·상태를 2차원 배열에 담아 한 번에 씁니다. MakeTable 로 'tbl메인' 표를 만들거나 크기만 바꾸고, 합계 행·BarByRate 데이터 막대·ColorStatus 글자색을 적용합니다. KpiRow 는 SUBTOTAL(109,tbl메인[예산현액]) 같은 수식 카드라 슬라이서로 거른 행만 합산합니다. 이어 modDetail 의 BuildGrouped 가 ItemSubtotals 결과로 '사업총액'/'세목' 행을 번갈아 놓은 세부현황 표를 같은 방식으로 만듭니다.
  8. modChart 351~479줄(BuildChartBoard)⑧ 예산보드: 수식 블록과 빈 행 자동 숨김BuildChartData(101-265줄)가 숨김 '차트자료' 시트에 세목 단위 원본 표 'tbl차트원본'을 만들고, 팀·세목·사업 TOP·담당자·KPI 블록에 VisF 가 만든 SUMPRODUCT(...SUBTOTAL(109,OFFSET(...))) 수식을 넣습니다. SortedBlock 은 LARGE·INDEX·MATCH 로 필터 결과를 다시 정렬하고, BuildChartBoard 는 예산보드 시트에 DrawKpi·GridRow 로 이 셀들을 참조하는 카드와 격자 표를 그린 뒤 오른쪽에 슬라이서 4개를 붙입니다. BX_SetHideName 으로 BX_HIDE_ 이름 범위를 등록하고 BX_EnsureBoardEvents 로 clsBoardEvents 를 연결하면, 슬라이서 선택 → 재계산 → App_SheetCalculate 가 빈 행을 숨깁니다.
  9. modCalc 69~248줄(BuildCalc)⑨ 세부산출내역 표와 메모 보존세부산출내역 시트가 이미 있으면 'tbl세부산출' 표의 키 열(세부사업|사업명|산출내역|세목코드|순서)과 메모 열을 Dictionary 에 먼저 담아 둡니다. 요구서 원본을 다시 훑어 소계·합계 행을 빼고 1레벨이면 번호를 떼어 내며, gItems 에서 팀·담당자·과제카드를 찾아 붙이고 같은 키의 메모를 되살립니다. 조건부 서식으로 레벨 1 행을 연파랑으로 칠하고, LeafSum 수식으로 세목코드가 있는 행만 합계를 내며, E7·G7 칸과 [찾기] 버튼(메모찾기)으로 자동 필터를 겁니다.

핵심 VBA 객체·함수

  • Application.GetOpenFilename(..., MultiSelect) — 파일 열기 대화상자를 띄워 경로를 받습니다. 취소하면 Boolean False 가 오므로 VarType(fp) = vbBoolean 으로 확인합니다.
  • Workbooks.Open(fileName, ReadOnly:=True, UpdateLinks:=0) — 원본 파일을 읽기 전용·외부 링크 갱신 없이 열어 값만 복사한 뒤 저장하지 않고 닫습니다.
  • Range.Value2 (2차원 배열 읽기/쓰기) — UsedRange 나 표 영역을 배열로 한 번에 읽고, 결과 배열을 Resize(n, m).Value2 = arr 로 한 번에 써서 셀 단위 반복보다 훨씬 빠릅니다.
  • CreateObject("Scripting.Dictionary") — 사업항목 키 → clsProject, 세목 → 금액 배열 등 키 기반 집계에 쓰는 사전 객체입니다. Exists 로 있는지 확인 후 누적합니다.
  • ListObjects.Add(xlSrcRange, rng, , xlYes) — 범위를 엑셀 표로 만듭니다. MakeTable 은 같은 이름의 표가 있으면 Resize 로 크기만 바꿔 슬라이서 캐시를 유지합니다.
  • SlicerCaches.Add2(표, 필드, 이름) / Slicers.Add — 표 열에 연결된 슬라이서를 만듭니다. 이미 있으면 위치·크기만 다시 지정하고, 새로고침 때는 ClearManualFilter 로 필터만 해제합니다.
  • SUBTOTAL(109, OFFSET(...)) + SUMPRODUCT — 필터로 숨겨진 행을 빼고 조건에 맞는 보이는 행만 합산하는 수식 패턴입니다. KPI·팀·세목 집계가 슬라이서에 즉시 반응하는 핵심입니다.
  • FormatConditions.AddDatabar / AddColorScale — 집행률 셀에 0~1 범위 데이터 막대(구간별 색)와 3색 스케일을 조건부 서식으로 넣습니다.

부르는 공통 함수

  • SpeedOn / SpeedOff (modUtil) — 화면 갱신·이벤트·자동 계산·경고를 끄고 상태 표시줄에 진행 문구 표시, 끝나면 복구
  • BW / IsBoardWB (modUtil) — 추가 기능으로 실행할 때 작업 대상 보드 통합문서(메인 또는 설정 시트 보유)를 찾거나 새로 만듦
  • GetSheet / SheetExists / ClearRowsKeepTables (modUtil) — 시트 확보·존재 확인, 표 머리글과 슬라이서는 남기고 내용만 비우기
  • FindHeaderRow / HeaderMap / HCol (modUtil) — 머리글 행 찾기, 머리글 이름→열 번호 사전, 필수 열이 없으면 오류 발생
  • CleanText / NormKey / MakeKey (modUtil) — 줄바꿈·특수 공백 제거, 공백·괄호 보충어를 없앤 매칭 키 '세부사업|사업항목' 생성
  • CfgGet / CfgSet (modUtil) — 숨김 '설정' 시트의 키/값(부서명·기준일·마지막갱신 등) 읽기·쓰기
  • AddButton / AddSlicerTo / DeleteOrClearSlicers (modUtil) — 매크로 연결 둥근 도형 버튼, 표 슬라이서 생성·재배치, 접두어별 슬라이서 삭제 또는 필터 해제
  • KpiRow / DrawKpi / StatusText / rate (modUtil) — 수식 KPI 카드 배치, 집행률 구간별 상태 문구, 0으로 나누기 방지 나눗셈

이렇게 고쳐 쓰세요

  • '완료' 상태 기준을 95%에서 90%로 낮추기 — modUtil 486줄 ElseIf rate >= 0.95 Then 의 0.95 를 0.9 로 바꿉니다. '정상' 기준은 488줄 0.5 입니다. 상태 글자는 BuildMain·BuildGrouped 가 새로고침 때 다시 계산하므로 [새로고침]만 누르면 반영됩니다.
  • 집행률 막대 색 구간(80%/60%) 바꾸기 — modChart 609줄 If rate >= 0.8 Then(파랑)과 611줄 ElseIf rate >= 0.6 Then(초록)의 숫자를 원하는 값으로 고칩니다. 메인·세부현황·예산보드가 모두 이 BarByRate 를 쓰므로 한 곳만 바꾸면 됩니다.
  • 예산보드의 사업항목 TOP 10 을 TOP 15 로 — modChart 16줄 Private Const TOPN As Long = 10 의 10 을 15 로 바꿉니다. 담당자 표 최대 행 수는 18줄 OWN_N, 세목 표는 17줄 SEM_N 입니다.
  • 강조 파랑을 조금 어둡게 — modUtil 58줄 ClrBlue = RGB(0, 122, 255) 를 RGB(0, 102, 204) 처럼 바꿉니다. VBA 의 RGB(빨, 초, 파) 는 사람이 읽는 순서로 쓰지만 결과 Long 값은 BGR 순서(&H00BBGGRR)라서 RGB(0,122,255) 는 &HFF7A00 입니다. 16진수로 직접 쓸 때는 파랑과 빨강 자리를 바꿔 써야 합니다.

고칠 때 주의

  • modMapping 298줄·309줄의 SpeedOn: BuildModel: SpeedOff 에서 줄 맨 앞 SpeedOn: 은 VBA 가 '줄 레이블'로 해석하므로 SpeedOn 이 실제로 호출되지 않습니다. 속도 모드를 켜려면 SpeedOn "...": BuildModel: SpeedOff 처럼 인수를 붙여 고쳐야 합니다.
  • 원본 열은 머리글 이름으로 찾습니다(HCol). 기관 예산시스템 내려받기 양식의 머리글(예: 예산현액, 사업항목명1)이 바뀌면 '헤더 ... 열을 찾지 못했습니다' 오류가 나므로, 해당 HCol 호출의 이름 문자열을 함께 고쳐야 합니다.
  • 금액 단위가 시트마다 다릅니다. ParseRequest 는 요구서 금액에 * 1000 을 곱해 원 단위로 맞추지만, 세부산출내역(modCalc)은 천원 단위 그대로 둡니다. 나눗셈은 0/0 오류를 피하도록 modUtil 의 rate() 를 쓰세요.

02키워드값 가져오기 정보가져오기

폴더 안 hwp·hwpx·pdf·이미지(Windows OCR)에서 성명·계좌번호 등 키워드 값을 찾아 파일별 한 행으로 정리합니다.

모듈 1개 · 1,225줄 · 리본 버튼 → 진입 프로시저 HK_Start (modHwpKeywordSheet)

modHwpKeywordSheet 표준 모듈 · 1,225줄

기능 전체를 담은 단일 모듈입니다. 시트·버튼 생성, 폴더 선택, 파일 형식별 문서 구조 읽기(hwpx/hwp/pdf/이미지 OCR), 키워드 값 판별 규칙, 결과 서식까지 1225줄 안에서 처리하며, 도형 버튼 서식만 공용 모듈(modRibbonUI)의 UI_StyleButton 을 빌려 씁니다.

소스 보기 (1,225줄)
심화과정: 소스 분석

리본 버튼이 HK_Start 를 불러 '키워드값' 시트와 [1 폴더선택]·[2 키워드값 가져오기] 도형 버튼을 만들고, 사용자는 3행 B~J 칸에 찾을 키워드를 적습니다. HK_Extract 는 폴더 안의 hwpx(압축 해제 후 MSXML 로 XML 파싱)·hwp(한글 자동화로 hwpx 임시 변환)·pdf(Word 로 열기)·이미지(PowerShell 로 Windows 내장 OCR) 파일을 모두 '표 + 문단' 블록 구조로 바꾼 뒤, 같은 규칙(같은 칸 '키워드: 값' → 오른쪽 칸 → 아래 칸 → 문단 뒤/다음 줄)으로 값을 찾아 파일당 한 행씩 기록합니다.

모듈 구성

  • modHwpKeywordSheet — 기능 전체를 담은 단일 모듈입니다. 시트·버튼 생성, 폴더 선택, 파일 형식별 문서 구조 읽기(hwpx/hwp/pdf/이미지 OCR), 키워드 값 판별 규칙, 결과 서식까지 1225줄 안에서 처리하며, 도형 버튼 서식만 공용 모듈(modRibbonUI)의 UI_StyleButton 을 빌려 씁니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modHwpKeywordSheet 49~111줄(HK_Start, HK_NewSheet, HK_CreateButtons)① 입력 시트와 버튼 만들기HK_Start 는 리본 콜백으로, HK_NewSheet 가 '키워드값'(이미 있으면 '키워드값_1', '_2' …) 시트를 맨 뒤에 추가합니다. HK_CreateButtons 는 Shapes.AddShape(msoShapeRoundedRectangle, ...) 로 둥근 도형 2개를 만들고 공용 UI_StyleButton 으로 HK_PickFolder·HK_Extract 를 연결합니다. 3행 B~J 에는 회색(RGB(150, 150, 150)) '키워드1~9' 자리표시자를 넣고, 5~6행에 사용 순서 안내를 적습니다.
  2. modHwpKeywordSheet 116~135줄(HK_PickFolder)② 대상 폴더 선택Application.FileDialog(msoFileDialogFolderPicker) 로 폴더를 고르게 하고, FileSystemObject 로 HK_IsSupported(hwp·hwpx·pdf·이미지, ~$ 임시 파일 제외)에 맞는 파일 수를 셉니다. A2 에 '대상폴더: 경로' 하이퍼링크를 달고 B2 에 대상 파일 개수를 표시합니다. 나중에 HK_FolderOf(250-266줄)가 이 링크 주소(또는 예전 방식의 B2)를 다시 읽어 폴더를 알아냅니다.
  3. modHwpKeywordSheet 140~248줄(HK_Extract)③ 파일별 반복과 형식 분기HK_ReadKeywords 가 3행에서 회색 자리표시자가 아닌 칸만 키워드로 모으고, 4행 아래 이전 결과를 지웁니다. 파일마다 확장자에 따라 HK_LoadHwpx / HK_LoadHwpViaHwpx / HK_LoadPdfViaWord / HK_LoadImageViaOcr 를 부르며, 한글·Word 객체는 처음 필요할 때 한 번만 만들어 재사용합니다. 읽기에 성공하면 키워드마다 HK_FindValue 결과를 텍스트 서식(@)으로 쓰고, A열에 값을 찾은 쪽 번호를 붙인 파일 링크, 12열(L)에 처리 상태를 남깁니다. 중간 오류는 HK_Fail 에서 한글·Word 를 종료한 뒤 문제 파일 이름을 알려 줍니다.
  4. modHwpKeywordSheet 626~729줄(HK_LoadHwpx, HK_WalkPara, HK_ParseTable)④ hwpx: XML 을 표·문단 블록으로HK_Unzip(753-788줄)이 파일을 .zip 으로 복사해 PowerShell Expand-Archive 로 풀고(실패 시 Shell.Application CopyHere 예비), Contents\section0.xml 부터 차례로 MSXML2.DOMDocument.6.0 에 읽습니다. HK_WalkPara 는 hp:run 안의 hp:t 글자를 한 줄로 모으다가 hp:tbl 을 만나면 HK_ParseTable 로 넘겨 문서 순서를 유지합니다. HK_ParseTable 은 hp:cellAddr 의 rowAddr/colAddr 와 hp:cellSpan 을 읽어 병합 범위 전체에 같은 글자와 같은 셀 번호(cid)를 채우므로, 뒤에서 병합 칸을 건너뛰고 '진짜 오른쪽 칸'을 찾을 수 있습니다.
  5. modHwpKeywordSheet 793~880줄(HK_CreateHwp, HK_LoadHwpViaHwpx, HK_HwpPageOf)⑤ hwp: 한글로 hwpx 임시 변환과 쪽 번호CreateObject("HWPFrame.HwpObject") 로 한글을 띄우고 보안 모듈 등록 후 창을 숨깁니다. 원본을 hwp.Open(path, "HWP", "forceopen:true") 로 열어 SaveAs 로 임시 hwpx 를 만든 뒤 ④의 HK_LoadHwpx 로 읽고, 실패하면 GetTextFile("UNICODE") 로 글자만 줄 단위로 읽는 예비 경로(HK_LoadHwpText)를 씁니다. 값을 찾으면 HK_HwpPageOf 가 HAction.Execute("RepeatFind", HFindReplace.HSet) 로 키워드를 찾고 KeyIndicator 의 쪽 번호를 받아 결과 파일명 옆에 '(p.3)' 처럼 표시합니다.
  6. modHwpKeywordSheet 896~935줄(HK_LoadPdfViaWord)⑥ pdf: Word 로 열어 표 읽기Word 는 pdf 를 열 때 편집 가능한 문서로 변환하므로, Documents.Open(path, False, True, False)(읽기 전용)로 연 뒤 문단을 차례로 봅니다. Range.Information(12) 가 참(표 안)이면 그 표를 시작 위치로 한 번만 등록해 셀마다 RowIndex·ColumnIndex 에 글자를 넣고, 아니면 문단 글자를 줄로 추가합니다. Information(3) 으로 얻은 쪽 번호를 표·줄에 함께 저장합니다.
  7. modHwpKeywordSheet 944~1112줄(HK_LoadImageViaOcr, HK_BuildOcrTable)⑦ 이미지: Windows OCR 단어 좌표로 표 흉내HK_OcrScript(1143-1181줄)가 만든 PowerShell 스크립트를 UTF-8 로 임시 폴더에 쓰고 WScript.Shell.Exec 로 실행해 최대 60초 기다립니다. 스크립트는 Windows.Media.Ocr.OcrEngine 으로 이미지를 1.4·1.2·1.0·1.7·2.0 배로 확대해 각각 인식하고, 단어마다 글자·x·y·폭·높이를 탭으로 구분해 돌려줍니다. HK_BuildOcrTable 은 단어를 세로 중심 차이(글자 높이의 0.6배 이내)로 행을 묶고, 글자 폭의 2.2배보다 넓은 빈틈으로 칸을 나눈 뒤, 칸 왼쪽 x 가 가까운 것끼리 같은 열 번호를 주어 하나의 표로 등록합니다. OCR 문서는 hkFuzzy = True 로 키워드 한 글자 오독을 허용합니다.
  8. modHwpKeywordSheet 328~397줄(HK_FindValue, HK_SearchTable)⑧ 값 판별 규칙HK_FindValue 는 blocks 배열(양수 = 문단, 음수 = 표)을 문서 순서대로 훑어 처음 값이 나온 곳에서 멈추고 그 쪽 번호를 돌려줍니다. HK_SearchTable 은 키워드 칸을 찾으면 먼저 같은 칸의 '키워드: 값'을 보고, cid 가 다른 첫 오른쪽 칸(vR)과 아래 칸(vB)을 구합니다. 같은 행의 다른 키워드 수가 같은 열보다 많으면 머리글 표로 보고 아래 칸을 우선하되, 오른쪽 칸이 라벨이 아닌 값이고 머리글 행이 아니면 다시 오른쪽을 우선합니다. 문단은 HK_SearchLine(428-455줄)이 '키워드 : 값' 또는 키워드만 있는 줄의 다음 문단을 값으로 씁니다.
  9. modHwpKeywordSheet 477~586줄(HK_IsKeywordCell ~ HK_Clean)⑨ 키워드 비교·라벨 판별·값 정리HK_Norm 은 공백·콜론·괄호·기호를 지우고 소문자로 바꿔 비교 기준을 맞춥니다. HK_AfterKeyword 는 키워드 바로 뒤가 한글·영문·숫자면('학교명', '성명란') 더 긴 라벨로 보고 버리며, 앞쪽 구분 기호와 '(한글)' 같은 괄호 보충어를 지웁니다. HK_LooksLabel 은 숫자 없는 6자 이하이면서 '명·번호·일자·주소…'로 끝나는 글을 값이 아닌 다음 항목명으로 판단하고, HK_Clean 은 값 뒤에 다른 키워드 라벨이 이어지면 그 앞에서 자르고 200자로 제한합니다. OCR 보정 HK_FuzzyFix(1185-1207줄)는 3자 이상 키워드와 길이가 같고 한 글자만 다른 조각을 키워드로 바꾸되 숫자 자리는 보정하지 않습니다.

핵심 VBA 객체·함수

  • Application.FileDialog(msoFileDialogFolderPicker) — 폴더 선택 대화상자입니다. .Show 가 -1 이면 .SelectedItems(1) 에 고른 폴더 경로가 들어 있습니다.
  • CreateObject("MSXML2.DOMDocument.6.0").Load — hwpx 의 section XML 을 DOM 으로 읽어 childNodes·nodeName·getAttribute("rowAddr") 등으로 표·문단 구조를 순서대로 탐색합니다.
  • WScript.Shell .Run / .Exec (powershell.exe) — Run 은 Expand-Archive 압축 해제를 끝날 때까지 기다리며(세 번째 인수 True) 실행하고, Exec 는 OCR 스크립트를 실행한 뒤 status 를 확인하며 기다립니다.
  • HWPFrame.HwpObject: Open / SaveAs(tmp, "HWPX") / GetTextFile — 한글 자동화로 hwp 를 열어 hwpx 사본으로 저장하거나, 실패 시 문서 글자 전체를 유니코드 텍스트로 가져옵니다.
  • hwp.HAction.Execute("RepeatFind", HParameterSet.HFindReplace.HSet) + KeyIndicator — GetDefault 로 찾기 매개변수를 채운 뒤 키워드를 앞으로 찾고, KeyIndicator 의 세 번째 출력값(인쇄 쪽 번호)을 읽어 값이 있는 쪽을 알아냅니다.
  • Word.Application: Documents.Open + Range.Information(3 / 12) — pdf 를 Word 로 열어 문단마다 쪽 번호(3 = wdActiveEndPageNumber)와 표 안 여부(12 = wdWithInTable)를 확인합니다.
  • Windows.Media.Ocr.OcrEngine.RecognizeAsync (PowerShell 안) — Windows 내장 OCR 로 이미지의 줄·단어와 단어별 BoundingRect 좌표를 얻습니다. 한국어 OCR 언어팩이 있어야 합니다.
  • ADODB.Stream (Charset = "utf-8") — PowerShell 스크립트를 UTF-8 로 저장하고, OCR 결과 텍스트 파일을 UTF-8 로 읽어 한글이 깨지지 않게 합니다.

부르는 공통 함수

  • UI_StyleButton (modRibbonUI) — 도형 버튼의 색·글꼴·여백을 꾸미고 OnAction 을 UI_ShapeClick 으로, AlternativeText 에 실행할 프로시저 이름(HK_PickFolder·HK_Extract)을 저장
  • UI_ShapeClick (modRibbonUI) — 클릭된 도형(Application.Caller)의 AlternativeText 를 읽어 UI_Run 으로 해당 프로시저를 실행
  • UI_Macro (modRibbonUI) — OnAction 에 넣을 매크로 이름 문자열을 돌려주는 도우미

이렇게 고쳐 쓰세요

  • 긴 값이 200자에서 잘리지 않게 — 25줄 Private Const MAX_VALUE_LEN As Long = 200 의 200 을 500 으로 바꿉니다. HK_Clean(584줄)이 이 길이를 넘으면 잘라 '…'를 붙입니다.
  • 키워드 칸을 9개(B~J)에서 13개(B~N)로 늘리기 — 23줄 KW_LAST_COL As Long = 10 을 14 로 바꿉니다. 이때 처리 상태 열이 12열(L)로 고정돼 있어 키워드 칸과 겹치므로, 147줄 ws.cells(3, 12) 와 217줄 ws.cells(r, 12) 의 12 를 16 으로 함께 바꿔야 합니다.
  • 이미지 OCR 속도 높이기(배율 줄이기) — 1160줄 PowerShell 문자열 @(1.4, 1.2, 1.0, 1.7, 2.0) 을 @(1.4, 1.0) 으로 줄이면 인식 횟수가 5번에서 2번으로 줄어듭니다. 인식률이 떨어질 수 있으므로 시험 후 정합니다. 기다리는 최대 시간은 960줄 Timer - T > 60 의 60(초)입니다.
  • 값으로 잘못 잡히는 항목명 추가 — 530줄 tails = Array("명", "번호", ...) 목록 끝에 , "직렬" 처럼 항목명 끝 글자를 추가하면, 숫자 없는 6자 이하이면서 그 글자로 끝나는 칸을 값이 아닌 다음 라벨로 보고 건너뜁니다.

고칠 때 주의

  • 한글 자동화의 Open·SaveAs 는 Boolean 대신 숫자 1 을 돌려줄 수 있어 Not ok 가 엉뚱하게 참이 됩니다. 810·820줄처럼 (... <> 0) 으로 정규화하는 부분은 지우지 마세요.
  • 자리표시자 판별은 글자색 RGB(150, 150, 150) 에 의존합니다(57줄에서 지정, 273줄에서 비교). 한쪽 색만 바꾸면 '키워드1' 같은 안내 글자가 실제 키워드로 검색됩니다.
  • hwpx 압축 해제와 OCR 은 powershell.exe -ExecutionPolicy Bypass 로 실행합니다. 보안 정책으로 PowerShell 실행이 막힌 PC 에서는 hwpx 는 Shell.Application 예비 경로로 넘어가지만, 이미지 OCR 은 '읽기 실패'로 남습니다.

03OFFICE파일합치기 OFFICE파일합치기

선택 폼 6항목: 한글→HWPX 하나로 / 한글→PDF / PDF 합치기(목차·링크) / Office 전부→PDF / 엑셀 파일들 합치기 / 시트들→하나로.

모듈 7개 · 1,886줄 · 리본 버튼 → 진입 프로시저 OfficeMergeMenu (modOfficeMenu)

modOfficeMenu 표준 모듈 · 52줄

리본 버튼(tag OfficeMergeMenu)의 진입점. 1차·2차 선택 카드로 작업과 방식을 고르고 해당 모듈의 실행 프로시저에 모드 번호를 넘깁니다.

소스 보기 (52줄)
modMergeHwp 표준 모듈 · 378줄

폴더 안 HWP·HWPX 를 한글 자동화 개체로 새 문서에 InsertFile 로 차례로 삽입해 '병합_날짜.hwpx' 로 저장하고 '한글병합' 시트에 목록을 남깁니다. 한글 개체 생성·정렬·저장 같은 보조 함수도 들어 있습니다.

소스 보기 (378줄)
modHwpToPdf 표준 모듈 · 197줄

폴더 안 HWP·HWPX 를 한 개씩 열어 SaveAs("PDF")로 변환하고 '변환 결과' 시트에 성공/실패를 기록합니다. 하나로 합치는 모드에서는 임시 폴더에 변환한 뒤 modMergePdf 의 MP_MergeFiles 에 넘깁니다.

소스 보기 (197줄)
modMergePdf 표준 모듈 · 494줄

PDF 목록을 Word 문서에 InsertFile 로 붙이고 파일마다 책갈피(BM_001…)를 달아, 선택 시 PAGEREF 필드와 내부 하이퍼링크로 된 목차 페이지를 맨 앞에 만든 뒤 PDF 로 내보냅니다.

소스 보기 (494줄)
modOfficeMerge 표준 모듈 · 278줄

한글·PDF·Word·Excel·PowerPoint·이미지를 이름순으로 Word 문서 하나에 넣어 'office병합_날짜.pdf' 로 내보냅니다. 형식마다 한글→PDF, 엑셀→PDF, 슬라이드→PNG 같은 중간 변환을 거칩니다.

소스 보기 (278줄)
modMergeExcelFiles 표준 모듈 · 423줄

폴더 안 엑셀 파일을 읽기 전용으로 열어 시트 내용을 새 통합 문서의 'Combined' 한 시트 또는 시트 이름별 시트로 모으고 '작업요약' 시트에 파일 목록을 남깁니다.

소스 보기 (423줄)
modMergeSheets 표준 모듈 · 64줄

현재 통합 문서에서 선택한 시트(1개만 선택하면 보이는 전체 시트)를 '시트모음' 시트 하나에 '시트명:' 제목과 함께 위에서 아래로 이어 붙입니다.

소스 보기 (64줄)
심화과정: 소스 분석

리본 진입점 OfficeMergeMenu 가 선택 카드(UI_Choose)로 여섯 가지 작업 중 하나를 고르게 한 뒤, 각 모듈의 실행 프로시저(MH_Run·HP_Run·MP_Run·OfficeMergeToPdf·MX_Run·MergeSheetsToCollection)를 부릅니다. 한글 파일은 COM 개체 HWPFrame.HwpObject 로 열어 InsertFile 액션으로 이어 붙이거나 SaveAs("PDF")로 변환하고, PDF·Office 파일은 숨겨 둔 Word 문서에 차례로 삽입한 뒤 ExportAsFixedFormat 으로 PDF 하나를 만듭니다. 엑셀 파일·시트 합치기는 Excel 개체 모델만으로 UsedRange 를 복사해 새 통합 문서나 '시트모음' 시트에 이어 붙입니다.

모듈 구성

  • modOfficeMenu — 리본 버튼(tag OfficeMergeMenu)의 진입점. 1차·2차 선택 카드로 작업과 방식을 고르고 해당 모듈의 실행 프로시저에 모드 번호를 넘깁니다.
  • modMergeHwp — 폴더 안 HWP·HWPX 를 한글 자동화 개체로 새 문서에 InsertFile 로 차례로 삽입해 '병합_날짜.hwpx' 로 저장하고 '한글병합' 시트에 목록을 남깁니다. 한글 개체 생성·정렬·저장 같은 보조 함수도 들어 있습니다.
  • modHwpToPdf — 폴더 안 HWP·HWPX 를 한 개씩 열어 SaveAs("PDF")로 변환하고 '변환 결과' 시트에 성공/실패를 기록합니다. 하나로 합치는 모드에서는 임시 폴더에 변환한 뒤 modMergePdf 의 MP_MergeFiles 에 넘깁니다.
  • modMergePdf — PDF 목록을 Word 문서에 InsertFile 로 붙이고 파일마다 책갈피(BM_001…)를 달아, 선택 시 PAGEREF 필드와 내부 하이퍼링크로 된 목차 페이지를 맨 앞에 만든 뒤 PDF 로 내보냅니다.
  • modOfficeMerge — 한글·PDF·Word·Excel·PowerPoint·이미지를 이름순으로 Word 문서 하나에 넣어 'office병합_날짜.pdf' 로 내보냅니다. 형식마다 한글→PDF, 엑셀→PDF, 슬라이드→PNG 같은 중간 변환을 거칩니다.
  • modMergeExcelFiles — 폴더 안 엑셀 파일을 읽기 전용으로 열어 시트 내용을 새 통합 문서의 'Combined' 한 시트 또는 시트 이름별 시트로 모으고 '작업요약' 시트에 파일 목록을 남깁니다.
  • modMergeSheets — 현재 통합 문서에서 선택한 시트(1개만 선택하면 보이는 전체 시트)를 '시트모음' 시트 하나에 '시트명:' 제목과 함께 위에서 아래로 이어 붙입니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modOfficeMenu 11~52줄(OfficeMergeMenu)① 리본 메뉴에서 작업 고르기13~21줄에서 UI_Choose 로 여섯 개 카드를 보여 주고, 돌려받은 번호를 22줄 Select Case choice 로 나눕니다. 1·2·3·5번은 한 번 더 UI_Choose 로 방식(서식 통합/구역 구분, 각각/목차/파일만, 이름별/한 시트)을 물어 sub1 에 담고, 0(취소)이면 바로 끝냅니다. 그 번호를 MH_Run sub1, HP_Run sub1, MP_Run sub1, MX_Run sub1 처럼 각 모듈에 그대로 넘기고, 4·6번은 OfficeMergeToPdf Nothing, MergeSheetsToCollection Nothing 으로 리본 인자 없이 호출합니다.
  2. modMergeHwp 18~114줄(MH_Run)② 한글 파일들을 HWPX 하나로27~29줄에서 모드에 따라 keepSec·keepFmt·asHwpx 값을 정합니다(1=구역·서식 유지 안 함, 2=유지). GetHwpObject 로 한글 개체를 만들고 창 숨김(42줄)과 RegisterModule "FilePathCheckDLL"(47줄)로 파일 접근 승인창을 막은 뒤 FileNew 로 빈 문서를 엽니다. ListHwpFiles 로 모은 경로를 QuickSortStrings 로 이름순 정렬하고, 65~77줄 반복문에서 파일마다 InsertFileToHwp 를 불러 실패한 이름만 모읍니다. 모드 1이면 78줄 MH_TrimTrailingEmpty 로 끝의 빈 문단을 지운 뒤 '병합_yyyymmdd_hhnnss.hwpx' 로 저장하고 '한글병합' 시트에 기록합니다.
  3. modMergeHwp 292~338줄(InsertFileToHwp, SaveAsHwp)③ InsertFile 액션과 HWPX 저장294줄 HAction.GetDefault "InsertFile" 로 파라미터 셋을 기본값으로 채우고 파일 이름과 KeepSection·KeepCharshape·KeepParashape·KeepStyle 을 넣은 다음 303줄 HAction.Execute 로 실행합니다. 이 네 값이 0이면 삽입 문서가 현재 문서(첫 문서) 서식을 따르고, 1이면 원래 구역·글자·문단 모양을 유지합니다. 저장은 316줄 hwp.SaveAs(savePath, "HWPX", "") 를 먼저 시도하고, 안 되면 FileSaveAs_S 액션에 Format = "HWPX" 를 지정하는 방식으로 한 번 더 시도합니다. 성공 여부는 Dir(savePath) 로 실제 파일이 생겼는지로 판단합니다.
  4. modHwpToPdf 13~80줄, 96-197 (HP_Run, HP_ConvertFolder)④ 한글 → PDF 일괄 변환HP_Run 은 모드 1이면 원본 폴더에, 2·3이면 '_pdf임시_시각' 하위 폴더에 PDF 를 만들도록 출력 폴더를 정합니다. HP_ConvertFolder 는 104~111줄에서 hwp/hwpx(임시파일 '~$', 이전 결과 '병합_' 제외)를 모아 버블 정렬하고, 한글 개체를 한 번만 만든 뒤 파일마다 163줄 objHwp.Open(filePath, "", "forceopen:true"), 167줄 objHwp.SaveAs(pdfPath, "PDF", "") 를 실행합니다. 결과는 C열에 '성공'(초록 RGB(0, 176, 80)) 또는 실패 사유(빨강)로 쓰고, 성공한 경로만 pdfPaths 배열에 담습니다. 모드 2·3이면 63줄에서 MP_MergeFiles 로 합친 뒤 임시 폴더를 지웁니다.
  5. modMergePdf 106~242줄(MP_MergeFiles)⑤ Word 로 PDF 이어 붙이기이미 실행 중인 Word 가 있으면 GetObject 로 빌려 쓰고, 없으면 CreateObject("Word.Application") 로 숨겨서 띄웁니다. 속도를 위해 ScreenUpdating 과 Options.Pagination 을 끄고, 150~188줄에서 파일마다 쪽 나누기 → 책갈피 BM_001 추가 → rng.InsertFile 순서로 넣습니다(실패하면 문서로 열어 복사·붙여넣기). 마지막에 페이지 계산을 다시 켜고 Repaginate·필드 갱신 후 207줄 ExportAsFixedFormat(CreateBookmarks:=2)로 PDF 를 저장하며, 원래 Word 가 열려 있지 않았을 때만 종료합니다.
  6. modMergePdf 305~447줄(BuildTOCPage)⑥ 목차 페이지와 내부 링크Selection.HomeKey 로 문서 맨 앞에 가서 '목 차' 제목, 구분선, 항목을 TypeText 로 입력합니다. 항목마다 탭 뒤에 Fields.Add ... "PAGEREF " & bmNames(i) 필드를 넣어 쪽 번호가 자동으로 계산되게 하고, 오른쪽 탭(점선 리더)으로 번호를 끝에 맞춥니다. 목차 뒤 쪽 나누기 다음 위치로 첫 책갈피를 다시 지정(403줄)해 첫 항목이 목차 쪽을 가리키지 않게 하고, 3번째 문단부터 탭 앞 글자에 Hyperlinks.Add SubAddress:=bmNames(i) 로 내부 링크를 겁니다.
  7. modOfficeMerge 16~102줄, 139-204 (OfficeMergeToPdf, OM_InsertOne)⑦ 여러 형식을 PDF 하나로OM_Collect 가 확장자를 OM_Kind 로 doc/img/pdf/hwp/xls/ppt 로 분류하고 이름순 정렬합니다. Word 새 문서(여백 1.5cm)에 파일마다 쪽 나누기를 넣고 OM_InsertOne 을 부르는데, doc 은 InsertFile, 이미지는 InlineShapes.AddPicture 로 쪽 폭에 맞춰 넣습니다. hwp 는 한글로 임시 PDF 를 만들고, xls 는 wb.ExportAsFixedFormat xlTypePDF 로 PDF 를 만든 뒤 OM_InsertPdf 로 넣으며, ppt 는 Slides(k).Export png, "PNG", 1600 으로 슬라이드를 그림으로 바꿔 넣습니다. 끝나면 'office병합_날짜.pdf' 로 내보내고 OM_Cleanup 이 임시 폴더와 한글·PowerPoint 개체를 정리합니다.
  8. modMergeExcelFiles 26~32줄, 39-345 (MX_Run, 시트합치기)⑧ 엑셀 파일들 합치기MX_Run 은 메뉴 번호를 모듈 변수 mxPresetMode 에 넣고 시트합치기 를 부릅니다(1→vbNo=이름별, 2→vbYes=Combined). 폴더의 xlsx/xls/xlsm/xlsb 를 모은 뒤 먼저 ProtectContents 로 보호 시트가 있는 파일을 알려 주고, Workbooks.Add 로 새 통합 문서와 '작업요약' 시트를 만듭니다. 파일마다 MX_OpenOrGet 으로 열어(이미 열린 파일은 그대로 사용) 각 시트의 UsedRange 를 C열부터 붙이고, A열에 파일 번호, B열에 파일 링크를 답니다. 보호된 시트는 서식 없이 .Value 만 옮기고, 이름별 모드에서는 Scripting.Dictionary 에 시트 이름과 다음 붙일 행(이름_p)을 함께 보관합니다.
  9. modMergeSheets 1~64줄(MergeSheetsToCollection, MergeCollectionCore, CopySheetContent)⑨ 현재 문서의 시트들 합치기선택한 시트가 1개면 확인 후 이름이 '시트모음'으로 시작하지 않고 보이는 시트 전부를, 여러 개면 선택한 워크시트만 Collection 에 담습니다. MergeCollectionCore 는 '시트모음', '시트모음_1' … 중 비어 있는 이름으로 새 시트를 맨 뒤에 만듭니다. CopySheetContent 는 Cells.Find("*", SearchDirection:=xlPrevious) 를 행·열 방향으로 두 번 써서 실제 마지막 행·열을 구하고, '시트명: …' 제목 한 줄 아래에 rng.Copy 로 붙인 뒤 두 줄을 띄웁니다.

핵심 VBA 객체·함수

  • hwp.HAction.GetDefault "InsertFile", hwp.HParameterSet.HInsertFile.HSet — 한글 '파일 끼워 넣기' 액션의 파라미터를 기본값으로 채웁니다. 이어서 FileName·KeepSection·KeepCharshape 등을 바꾸고 HAction.Execute 로 실행합니다.
  • hwp.RegisterModule "FilePathCheckDLL", "FilePathCheckerModule" — 한글 자동화에서 파일을 열거나 저장할 때 뜨는 접근 승인 창을 띄우지 않도록 보안 모듈을 등록합니다(해당 모듈이 PC 에 등록되어 있어야 효과가 있습니다).
  • hwp.Open(path, "", "forceopen:true") / hwp.SaveAs(path, "PDF", "") — 한글 문서를 열고 PDF 형식으로 다른 이름 저장합니다. 반환값이 0이 아니면 성공으로 처리합니다.
  • Range.InsertFile FileName:=p, ConfirmConversions:=False (Word) — Word 문서의 지정 위치에 다른 파일 내용을 끼워 넣습니다. PDF 는 Word 의 PDF 변환 기능을 거쳐 들어갑니다.
  • wdDoc.Fields.Add Range, -1, "PAGEREF BM_001" — 책갈피가 있는 쪽 번호를 표시하는 필드를 만듭니다. 목차의 쪽 번호가 이 필드로 자동 계산됩니다.
  • wdDoc.ExportAsFixedFormat OutputFileName, 17, CreateBookmarks:=2 — Word 문서를 PDF(17)로 내보내며, 문서의 책갈피를 PDF 책갈피로 함께 만듭니다.
  • Workbook.ExportAsFixedFormat Type:=xlTypePDF — 엑셀 통합 문서를 PDF 로 저장합니다. Office 합치기에서 엑셀 파일을 Word 에 넣기 전 중간 PDF 를 만들 때 씁니다.
  • Worksheet.UsedRange.Copy Destination — 시트에서 사용 중인 범위를 서식과 함께 다른 시트의 지정 셀로 복사합니다. 보호된 시트는 대신 .Value 를 대입해 값만 옮깁니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 숫자 입력 대신 카드 형태 선택 폼을 띄우고 고른 번호(취소=0)를 돌려줌
  • UI_ChoiceToMsg (modRibbonUI) — 선택 번호 1/2/그 외를 vbYes/vbNo/vbCancel 로 바꿔 기존 MsgBox 방식 코드와 연결
  • BX_Trace (modRibbonUI 공용 변수) — 긴 작업의 현재 단계를 적어 두었다가 오류 메시지에 '@단계'로 붙임
  • MP_MergeFiles (modMergePdf) — PDF 목록을 Word 로 합치는 공용 코어. 한글→PDF 하나로 합치기(HP_Run)에서도 재사용

이렇게 고쳐 쓰세요

  • PDF 합치기 결과의 여백을 2cm 에서 1.5cm 로 — modMergePdf 141~144줄의 wdApp.CentimetersToPoints(2) 네 곳을 wdApp.CentimetersToPoints(1.5) 로 바꿉니다. 목차 탭 위치는 313줄에서 여백을 빼서 계산하므로 따로 고칠 필요가 없습니다.
  • 목차 링크 글자색을 진파랑에서 진빨강으로 — modMergePdf 441줄 RGB(0, 51, 153) 을 RGB(192, 0, 0) 으로 바꿉니다. VBA 의 RGB(빨강, 초록, 파랑) 함수는 사람이 읽는 순서로 쓰지만, 결과 Long 값은 내부적으로 0x00BBGGRR(BGR) 순서이므로 숫자로 직접 쓸 때는 &H0000C0 처럼 빨강이 맨 뒤 두 자리에 옵니다.
  • PowerPoint 슬라이드 그림을 더 선명하게 — modOfficeMerge 185줄 pres.Slides(k).Export png, "PNG", 1600 의 1600(내보내는 그림 가로 픽셀)을 2400 으로 올립니다. 그림은 OM_AddPicture 가 쪽 폭에 맞춰 줄이므로 크기는 같고 해상도만 올라가며, 결과 PDF 용량은 커집니다.
  • 한글 합치기 결과를 HWPX 대신 HWP 로 저장(모드 1) — modMergeHwp 27줄 Case 1: keepSec = 0: keepFmt = 0: asHwpx = True 의 True 를 False 로 바꾸면 84줄 경로('.hwp')와 SaveAsHwp 의 FileSaveAs_S 경로를 탑니다.

고칠 때 주의

  • 결과 파일 이름 앞머리 '병합_' 은 다음 실행 때 결과물이 다시 합쳐지지 않도록 수집 단계에서 제외하는 표시이기도 합니다(modMergeHwp 238·246줄, modHwpToPdf 106줄, modMergePdf 260·270줄, modOfficeMerge 109줄). 접두어를 바꾸면 이 비교들도 함께 바꿔야 합니다.
  • 목차 링크는 '1문단=제목, 2문단=구분선, 3문단부터 항목'이라는 가정(modMergePdf 411줄 tocStartPara = 3)으로 문단 번호를 계산합니다. 목차 위에 문단을 추가하면 이 값도 늘려야 링크가 맞는 줄에 걸립니다.
  • 엑셀 합치기의 모드 번호는 메뉴(1=이름별, 2=한 시트)와 내부 값(vbNo=이름별, vbYes=Combined)이 반대로 대응됩니다(modMergeExcelFiles 75~76줄). 선택지 순서를 바꿀 때 두 곳을 함께 확인하세요.

04폴더/파일 이름변경 폴더정리

파일 이름을 단어로 나눠 지정 단어만 조합해 일괄 변경, 중복 단어 목록에서 O 표시 단어만 삭제.

모듈 1개 · 707줄 · 리본 버튼 → 진입 프로시저 p001_폴더선택 (modRenameFiles)

modRenameFiles 표준 모듈 · 707줄

목록 시트 생성, 단어 추출·조합, 중복 단어 정리, 실제 이름 변경까지 이름변경 기능 전체를 담은 모듈입니다. 버튼으로 불리는 Public 프로시저(p001~p005)와 시트 서식·이름 찾기용 Private 보조 함수로 구성됩니다.

소스 보기 (707줄)
심화과정: 소스 분석

리본 진입점 p001_폴더선택 이 고른 폴더의 하위 폴더·파일 이름을 '폴더'/'파일'/'폴더및파일' 시트에 나열하고, 1행에 단계별 도형 버튼 6개를 만들어 이후 작업을 버튼 매크로로 이어 갑니다. 이름은 구분 문자(_-.,() 등)를 빈칸으로 바꿔 단어로 나눈 뒤, 입력한 단어가 든 조각을 뽑아 조합하거나 여러 이름에 공통으로 든 단어를 지워 D열 '이름 변경'에 새 이름을 만듭니다. 마지막 단계에서 금지 문자·중복 이름을 검사하고 VBA 의 Name 원본 As 새경로 문으로 실제 이름을 바꾼 결과를 E열에 표시합니다.

모듈 구성

  • modRenameFiles — 목록 시트 생성, 단어 추출·조합, 중복 단어 정리, 실제 이름 변경까지 이름변경 기능 전체를 담은 모듈입니다. 버튼으로 불리는 Public 프로시저(p001~p005)와 시트 서식·이름 찾기용 Private 보조 함수로 구성됩니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modRenameFiles 10~96줄(p001_폴더선택)① 대상 고르기와 목록 시트 만들기24줄 UI_Choose 로 '폴더/파일/폴더 및 파일' 중 하나를 고르고, 폴더 선택 대화상자로 기준 폴더를 받습니다. 선택에 따라 시트 이름을 정한 뒤 48~52줄에서 같은 이름 시트를 경고 없이 지우고 새로 만듭니다. Scripting.FileSystemObject 의 SubFolders(숨김 속성 vbHidden 제외)와 Files('.tmp'·'~$' 제외)를 돌며 B열에 앞 공백 2칸을 붙인 이름, C열에 '폴더' 또는 확장자를 4행부터 적습니다. B2에는 기준 폴더 경로를 하이퍼링크로 넣어 이후 단계가 이 경로를 다시 읽습니다.
  2. modRenameFiles 609~648줄(CreateMacroButtons, SetupHeaders)② 단계 버튼과 표 머리CreateMacroButtons 는 이름·글자·매크로 배열 세 개를 같은 순서로 두고 1행에 둥근 사각형 6개를 116pt 간격으로 만든 뒤 UI_StyleButton 으로 버튼 모양을 꾸밉니다. 이때 실행할 프로시저 이름은 도형의 대체 텍스트(AlternativeText)에 저장되고, 클릭하면 공통 처리기 UI_ShapeClick 이 그 이름을 읽어 실행합니다. 마지막 '6 이름 변경'만 i = 5 조건으로 강조 버튼이 됩니다. SetupHeaders 는 D~Z열을 텍스트 서식("@")으로 바꿔 '0926' 같은 숫자 이름이 숫자로 바뀌지 않게 하고, 3행에 No.·이름·정보·이름 변경·결과, 2행 F~J열에 '단어입력1~5' 머리글을 씁니다.
  3. modRenameFiles 105~156줄, 670-698 (p002_이름가져오기, UpdateCombinedName, ReplaceCharsWithSpace)③ 단어 추출과 이름 조합3행 F열부터 입력된 단어(키워드)를 열마다 읽고, 각 행의 B열 이름을 ReplaceCharsWithSpace 로 정리해 Split(…, " ") 로 나눕니다. 조각 중 키워드를 포함하는(InStr … vbTextCompare, 대소문자 무시) 첫 조각을 그 열에 넣고, UpdateCombinedName 이 F열부터 마지막 열까지 값이 있는 칸을 빈칸으로 이어 D열 '이름 변경'에 씁니다. ReplaceCharsWithSpace 는 689줄 문자 목록을 빈칸으로 바꾸고 연속 빈칸을 하나로 줄입니다. 사용한 키워드 칸은 연두색 RGB(144, 238, 144) 로 표시됩니다.
  4. modRenameFiles 161~224줄(p_단어입력추가, p003_이름새로설정)④ 입력 열 추가와 수동 조합'3 입력 추가' 버튼은 2행 마지막 머리글 다음 열에 '단어입력N' 을 만들고 텍스트 서식을 적용합니다. '4 이름 조합' 버튼은 3행에 키워드가 있는데 아래가 비어 있는 열을 찾아 4행~마지막 행에 그 키워드를 통째로 채웁니다(213줄). 그다음 모든 행에 UpdateCombinedName 을 다시 불러, 사용자가 F열 이후 칸을 직접 고친 내용까지 D열 새 이름에 반영합니다.
  5. modRenameFiles 378~461줄, 550-562 (p005_중복단어삭제 1회차, SortDictKeysByValue)⑤ 공통 단어 목록 만들기391줄 조건(P3='중복 단어', P4 값 있음, P2 가 '적용됨' 아님)에 맞으면 2회차로 넘어가고, 아니면 1회차를 실행합니다. 1회차는 이름마다 seen 사전으로 같은 이름 안의 중복을 한 번만 세고, 전체 사전 dict 에 '그 단어가 든 이름 수'를 누적합니다(두 사전 모두 CompareMode = vbTextCompare). SortDictKeysByValue 로 많이 나온 순으로 정렬해 2개 이상 이름에 나온 단어만 P열(단어)·Q열(이름 수)·R열('O')에 쓰고, 표 위에 'O 삭제 항목만 삭제' 버튼을 만듭니다.
  6. modRenameFiles 466~547줄(p005_중복단어적용, DupApply, CreateDupApplyButton)⑥ 표시한 단어 지우기DupApply 는 R열이 'O'인 P열 단어만 사전에 담고, 각 이름을 다시 단어로 나눠 그 단어를 뺀 나머지를 빈칸으로 이어 D열에 씁니다. onlyMarked 가 False(5번 버튼 두 번째 클릭)면 seen 사전으로 한 이름 안에서 반복된 단어도 하나만 남깁니다. 모두 지워져 빈 이름이 되면 원래 이름을 유지하고(515줄), 바뀐 행은 E열에 '이름 변경 대기'를 연한 노랑으로 표시하며 P2 에 '적용됨'을 남깁니다.
  7. modRenameFiles 229~369줄(p004_이름변경)⑦ 검사 후 실제 이름 바꾸기B2 하이퍼링크 주소(없으면 셀 값)로 기준 폴더를 읽고 UI_Choose 로 한 번 더 확인합니다. 행마다 새 이름 비어 있음 → 금지 문자 \/:*?"<>| → 원본 찾기(FindActualFileName) → UI_ValidFolderName → 같은 이름이면 건너뜀 → 대상 이름이 이미 있음 순서로 검사하고, 실패하면 E열에 사유와 연한 빨강을 쓰고 GoTo NextItem 으로 넘어갑니다. 파일은 C열 확장자를 다시 붙이고(310줄), 351줄 Name oldPath As newPath 로 이름을 바꾼 뒤 성공하면 B열도 새 이름으로 고칩니다.
  8. modRenameFiles 570~607줄(FindActualFileName)⑧ 시트 이름과 실제 파일 맞추기시트의 B열 이름은 사용자가 고쳤거나 구분 문자가 바뀌었을 수 있으므로, 먼저 폴더(또는 같은 확장자 파일)에서 이름이 정확히 같은 항목을 찾습니다. 없으면 두 번째 반복에서 양쪽을 ReplaceCharsWithSpace 로 정리해 비교하고, 맞는 항목이 정확히 1개일 때만 실제 이름(확장자 포함)을 돌려줍니다. 2개 이상이면 빈 문자열을 돌려줘 엉뚱한 파일이 바뀌지 않게 합니다.

핵심 VBA 객체·함수

  • CreateObject("Scripting.FileSystemObject").GetFolder(path).SubFolders / .Files — 폴더 안 하위 폴더와 파일 컬렉션을 돌려줍니다. 각 항목의 Name·Path·Attributes 로 이름과 숨김 여부를 확인합니다.
  • fso.GetBaseName / fso.GetExtensionName — 경로에서 확장자를 뺀 이름과 확장자만 따로 뽑습니다. 목록 시트의 B열(이름)과 C열(확장자)을 채울 때 씁니다.
  • Name oldPath As newPath — VBA 내장 문으로 파일이나 폴더 이름을 바꿉니다(같은 드라이브 안에서는 이동도 됨). 실패하면 오류가 나므로 On Error Resume Next 후 Err.Number 로 결과를 판단합니다.
  • CreateObject("Scripting.Dictionary") + CompareMode = vbTextCompare — 단어별 개수를 세는 사전입니다. 텍스트 비교 모드라 대소문자가 달라도 같은 단어로 셉니다.
  • ws.Shapes.AddShape(msoShapeRoundedRectangle, x, y, w, h) — 시트 위에 둥근 사각형 도형을 만듭니다. UI_StyleButton 이 여기에 글자와 연결 매크로를 넣어 단계 버튼으로 씁니다.
  • Range.DataSeries Rowcol:=xlColumns, Type:=xlLinear, Step:=1 — A4 의 1부터 아래로 1씩 증가하는 번호를 채웁니다. 항목이 1개일 때 오류가 나므로 665줄에서 lastRow > 4 일 때만 실행합니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 대상 종류 선택과 이름 변경 실행 확인 카드
  • UI_StyleButton (modRibbonUI) — 도형 색·글자를 꾸미고 실행할 프로시저 이름을 AlternativeText 에 저장(클릭 시 UI_ShapeClick 이 실행)
  • UI_ValidFolderName (modRibbonUI) — 빈 이름, 끝의 점·공백, 제어 문자, 금지 문자, CON·PRN 등 예약 이름을 걸러 냄

이렇게 고쳐 쓰세요

  • 물결(~)과 작은따옴표도 단어 구분 문자로 처리 — 689줄 specialChars = "_-.,()[]{}!@#$%^&+=" 의 따옴표 안 끝에 ~' 를 덧붙입니다. 이 함수는 단어 추출, 중복 단어 정리, 원본 파일 찾기(FindActualFileName)에서 모두 쓰이므로 세 기능에 함께 적용됩니다.
  • 3개 이상 이름에 나온 단어만 중복 단어로 표시 — 420줄 If dict(keys(i)) >= 2 Then 의 2 를 3 으로 바꿉니다. 452줄 안내 문구의 '2개 이상'도 함께 고쳐 두면 헷갈리지 않습니다.
  • 이름 변경 성공 표시색을 연두에서 하늘색으로 — 354줄 RGB(200, 255, 200) 를 RGB(204, 236, 255) 로 바꿉니다. RGB() 함수 인자는 빨강·초록·파랑 순서지만, 셀 Interior.Color 에 숫자를 직접 넣을 때는 0x00BBGGRR(BGR) 순서라 &HFFECCC 가 같은 색입니다.
  • 처음 만들어지는 단어입력 열을 5개에서 3개로 — SetupHeaders 의 632~633줄(I2·J2 머리글)을 지우고 641·647줄 범위 A3:J3·F3:J3 를 A3:H3·F3:H3 으로 줄입니다. 124·206줄의 lastCol = 10 은 머리글이 없을 때의 기본값이므로 8 로 맞춥니다.

고칠 때 주의

  • 목록을 다시 만들면 48~52줄에서 같은 이름의 '폴더'/'파일'/'폴더및파일' 시트를 경고 없이 삭제합니다. 작업 내용을 남기려면 시트 이름을 바꿔 두거나 이 부분에 확인 창을 넣으세요.
  • B열 이름에는 정렬용 앞 공백 2칸이 붙어 있고 코드가 Trim 으로 지워 비교합니다. 다른 곳에서 B열을 읽도록 고칠 때도 Trim 을 빼먹으면 원본을 찾지 못합니다.
  • Name … As … 로 바뀐 이름은 되돌리기(Ctrl+Z)가 되지 않습니다. 시험할 때는 복사본 폴더에서 실행하세요.

05폴더/파일 정리 폴더정리

이름 속 키워드로 폴더를 추천해 기준 폴더로 자동 이동(분류_결과 시트에서 확인 후 이동, 폴더 다시 선택 버튼).

모듈 1개 · 1,876줄 · 리본 버튼 → 진입 프로시저 폴더분석정리 (modFolderClassify)

modFolderClassify 표준 모듈 · 1,876줄

폴더 분석, 단어 빈도 기반 분류 추천, 기준폴더 키워드 표, 이동·날짜 이름 정리·이름 변경까지 폴더/파일 정리 기능 전체를 담은 모듈입니다(1876줄). 진입점과 시트 버튼용 Public 프로시저, 분석·매칭·서식용 Private 함수로 나뉩니다.

소스 보기 (1,876줄)
심화과정: 소스 분석

리본 진입점 폴더분석정리 가 '기준폴더 설정' 또는 폴더/파일/폴더및파일 분석 중 하나를 고르게 하고, 분석은 FC_RunAnalysis 가 FileSystemObject 로 항목을 나열해 '분류_결과' 시트에 표로 씁니다. 이름을 정규식으로 단어로 나눠 Scripting.Dictionary 로 빈도를 세고, 날짜·숫자류 단어를 뺀 뒤 각 항목 이름에 든 가장 흔한 단어를 E열 '이동 폴더'로 추천합니다(기준폴더가 설정돼 있으면 그 하위 폴더별 키워드 표와 대조). 사용자가 E·F열을 확인·수정한 뒤 1행 버튼을 누르면 MoveFile/MoveFolder 로 실제 이동·이름 변경을 하고 결과를 G열에 남깁니다.

모듈 구성

  • modFolderClassify — 폴더 분석, 단어 빈도 기반 분류 추천, 기준폴더 키워드 표, 이동·날짜 이름 정리·이름 변경까지 폴더/파일 정리 기능 전체를 담은 모듈입니다(1876줄). 진입점과 시트 버튼용 Public 프로시저, 분석·매칭·서식용 Private 함수로 나뉩니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modFolderClassify 34~62줄(폴더분석정리)① 메뉴와 기준폴더 상태 표시먼저 FC_BasePath() 로 현재 통합 문서의 '기준폴더' 시트 B2(하이퍼링크 주소 우선)를 읽어 안내 문구를 만들고, UI_Choose 로 네 가지 메뉴를 보여 줍니다. 1번을 고르면 FC_SetBasePathDialog 로 기준폴더 시트만 만들고 끝나며, 분석은 그 시트 1행 버튼(FC_분석_폴더 등)에서 이어집니다. 2~4번은 분석 유형 문자열('폴더'·'파일'·'폴더및파일')로 바꿔 FC_RunAnalysis 를 부릅니다. 기준폴더 경로를 레지스트리가 아니라 시트에 두므로, 그 파일을 저장해 두면 다음에도 같은 설정을 씁니다.
  2. modFolderClassify 251~381줄(FC_SetBasePathDialog, FC_BuildBaseSheet)② 기준폴더 시트: 폴더별 키워드 표FC_BuildBaseSheet 는 기준폴더의 하위 폴더마다 새 사전을 만들고, 폴더 이름을 FC_CollectWordFreq 에 두 번 넣어(329~330줄, 가중치 2) 안의 파일 이름 단어와 함께 빈도를 셉니다. FC_TopKeywords 로 상위 15개(KW_MAX)를 골라 C열부터 '키워드1~15' 칸에 쓰고, 마지막 열에 파일 수를 적습니다. 키워드 칸은 연한 노랑 RGB(255, 251, 235) 로 '수정 가능'을 표시하며, 사용자가 고친 키워드는 나중에 FC_ReadBaseMapping 이 그대로 읽어 씁니다. 1행에는 초록 분석 버튼 3개와 '기준폴더 다시 읽기' 버튼을 만듭니다.
  3. modFolderClassify 76~134줄, 1416-1452 (FC_RunAnalysis 앞부분, FC_CreateMoveButton)③ 분석 준비와 결과 시트 틀분류 키워드 배열 kwArr 는 빈 값 하나로 고정하고(81~82줄) 폴더 선택 대화상자로 분석 폴더를 받습니다. 화면 갱신과 자동 계산을 끈 뒤 FC_GetOrCreateSheet("분류_결과") 를 비우고, FC_CreateMoveButton 이 1행에 이동·기준폴더·날짜 형식·이름 변경 버튼 10개와 설명 도형을 배치합니다. 2행 B2 에 분석 폴더를 하이퍼링크로 넣고, 3행에 NO·폴더명·파일명·확장자·이동 폴더·이름 변경(안)·이동결과·분석 추천·추천 근거(A~I열) 머리글을 씁니다.
  4. modFolderClassify 865~1046줄, 828-840 (FC_AnalyzeFolders/Files/FoldersAndFiles, FC_SkipItem)④ 항목 나열과 단어 빈도 수집분석 유형에 따라 하위 폴더만, 최상위 파일만, 또는 최상위 파일 → 하위 폴더 → 그 안의 파일 순서로 한 행씩 씁니다. FC_SkipItem 은 '~$'·'$' 로 시작하는 이름, desktop.ini·thumbs.db, 숨김 속성(폴더는 And 2, 파일은 숨김+시스템 And 6)을 건너뜁니다. 각 이름은 FC_CollectWordFreq 로 전역 사전 globalFreq 에 누적되고, 진행률은 Application.StatusBar 에 백분율로 표시됩니다. 파일 내부 텍스트 검색(FC_ExtractFileText)은 키워드가 있을 때만 실행되도록 FC_HasKeywords 로 막혀 있습니다.
  5. modFolderClassify 1214~1263줄(FC_IsNumberLike, FC_CollectWordFreq, FC_CleanText)⑤ 정규식으로 단어 다듬기FC_CleanText 는 VBScript.RegExp 로 한글·영문·숫자 이외 문자를 빈칸으로 바꾸고([^가-힣a-zA-Z0-9]), 숫자만으로 된 단어와 연속 공백을 정리합니다. FC_CollectWordFreq 는 2글자 이상이면서 FC_IsNumberLike 가 아닌 단어만 사전에 셉니다. FC_IsNumberLike 는 숫자만 있는 단어와, 1219줄 정규식 ^\d+(년도|년|월|일|차|회|…)$ 에 맞는 '2026년'·'3차'·'2학기' 같은 단어를 걸러 냅니다.
  6. modFolderClassify 1266~1319줄, 476-512 (FC_FillRecommendations, FC_WriteKeywordTable)⑥ E열 이동 폴더 자동 추천전체 빈도 상위 5개(2회 이상)를 F2 에 '자동 추천 키워드'로 적고, E열이 빈 행마다 그 이름의 단어 중 전체 빈도가 가장 높은 단어(bestN = 1 에서 시작하므로 2회 이상)를 고릅니다. 고른 단어가 UI_ValidFolderName 을 통과하면 E열에 쓰고 I열에 '이름에 'OO' 포함 (전체 N회)' 근거를 남기며, 없으면 '미분류'로 둡니다. 이어 FC_WriteKeywordTable 이 K열부터 3열(순위·키워드·빈도)에 분석 키워드 상위 15개 표를 만듭니다.
  7. modFolderClassify 538~604줄, 414-432, 810-824 (FC_ApplyBaseKeywords, FC_MatchBaseFolder, FC_ResolveDest)⑦ 기준폴더 키워드와 대조기준폴더가 설정돼 있으면 O열부터 기준 키워드 표를 쓰고, '기준폴더' 시트 표를 읽어(경로가 다르면 시트를 새로 만듦) 행마다 FC_MatchBaseFolder 를 부릅니다. 이 함수는 폴더별 키워드 중 이름에 들어 있는 개수를 세어 가장 많이 맞는 폴더(동점이면 위쪽 행)를 돌려줍니다. 표에서 못 찾으면 상위 키워드 단순 포함 검사 후 FC_ResolveDest 로 키워드를 포함한 기존 하위 폴더 중 이름이 가장 짧은 것을 고릅니다. 원래 추천은 H열 '분석 추천(참고)'에 보관하고, 맞는 폴더가 없으면 E열을 '미분류'로 바꿉니다.
  8. modFolderClassify 658~807줄, 1363-1410 (FC_MoveAll, FC_GetUniquePath)⑧ 미리보기 후 실제 이동먼저 G열이 '성공'이 아닌 행을 훑어 E열 폴더별 이동 개수를 사전에 모으고, UI_Choose 로 '폴더별 이동 항목 수' 미리보기를 보여 승인받습니다. 승인되면 행마다 원본·대상 경로를 만들고, 폴더를 자기 자신이나 하위 폴더로 옮기는 경우와 이미 그 폴더에 있는 파일은 건너뜁니다. 대상 폴더가 없으면 CreateFolder 로 만들고, FC_GetUniquePath 가 같은 이름이 있을 때 '_1', '_2' 를 붙인 경로를 찾은 뒤 MoveFolder/MoveFile 로 옮깁니다. 폴더째 옮긴 경우 그 안 파일 행은 '폴더와 함께 이동됨'으로 처리합니다.
  9. modFolderClassify 1458~1502줄, 1558-1634, 1693-1766 (FC_NormalizeDate, FC_CycleNameFormat, FC_ApplyRenames)⑨ 날짜 정규화와 이름 변경FC_NormalizeDate 는 정규식 네 개를 순서대로 시도해 '2026.09.26'·'2026.3.5'·'260926'·'0926(올해)' 같은 날짜를 YYYYMMDD 로 바꾸고, 찾은 날짜를 found 로 돌려줍니다. FC_CycleNameFormat 은 버튼을 누를 때마다 H2/I2 셀에 저장한 순번을 1→4로 돌리며 '키워드 월일', '키워드-YYYYMMDD' 같은 형식의 새 이름을 F열 '이름 변경(안)'에 씁니다. FC_ApplyRenames 는 F열 값으로 MoveFile/MoveFolder 를 써서 같은 폴더 안에서 이름을 바꾸고, 폴더 이름이 바뀌면 그 폴더에 속한 파일 행의 B열도 함께 고칩니다.

핵심 VBA 객체·함수

  • CreateObject("VBScript.RegExp") — .Pattern / .Test / .Execute(…)(0).SubMatches — 정규식으로 특수문자 정리, 날짜·숫자 단어 판별, 날짜 토큰 추출을 합니다. SubMatches(n) 으로 괄호 그룹(연·월·일)을 꺼냅니다.
  • CreateObject("Scripting.Dictionary") + CompareMode = vbTextCompare — 단어 → 빈도, 폴더명 → 이동 개수를 담는 사전입니다. Exists 로 있는지 확인한 뒤 값을 1씩 늘립니다.
  • fso.MoveFile / fso.MoveFolder / fso.CreateFolder — 파일·폴더를 다른 경로로 옮기거나(같은 폴더 안이면 이름 변경) 대상 폴더를 만듭니다. 대상에 같은 이름이 있으면 오류가 나므로 FC_GetUniquePath 로 먼저 피합니다.
  • Folder.SubFolders / Folder.Files / item.Attributes — 하위 폴더·파일을 나열하고, 속성 비트(2=숨김, 4=시스템)로 분석 대상에서 뺄 항목을 판단합니다.
  • Application.FileDialog(msoFileDialogFolderPicker) — 폴더 선택 대화상자를 띄웁니다. 기준폴더 설정에서는 .InitialFileName 으로 이전 기준폴더를 시작 위치로 줍니다.
  • ws.Shapes.AddShape(msoShapeRoundedRectangle, …).TextFrame2 — 1행 버튼과 설명 도형을 만듭니다. FC_AddNote 는 TextFrame2 로 여백·줄바꿈·글꼴을 지정해 안내 상자를 그립니다.
  • ws.Hyperlinks.Add Anchor, Address, TextToDisplay — B2 분석 폴더, 기준폴더 경로, 하위 폴더 이름에 탐색기로 열리는 링크를 겁니다. 이후 단계는 이 하이퍼링크 주소를 경로로 다시 읽습니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 첫 메뉴, 이동 미리보기·이름 변경 실행 확인 카드
  • UI_StyleButton (modRibbonUI) — 1행 도형 버튼의 색·글자 지정과 실행할 프로시저 연결(AlternativeText)
  • UI_ValidFolderName (modRibbonUI) — 추천 키워드·E열 폴더명·F열 새 이름이 Windows 이름 규칙에 맞는지 검사

이렇게 고쳐 쓰세요

  • 키워드 표를 15개에서 10개로 줄이기 — 25줄 Private Const KW_MAX As Long = 15 의 15 를 10 으로 바꿉니다. 기준폴더 시트의 '키워드1~N' 열, K열·O열 키워드 표, 표 읽기 범위가 모두 이 상수를 쓰므로 한 곳만 고치면 됩니다. 186줄 완료 메시지의 '키워드 15개' 문구는 따로 고칩니다.
  • 세 글자 이상 단어만 분류 키워드로 쓰기 — 1233줄 If Len(W) >= 2 And … 와 1300줄 If Len(W) >= 2 And … 의 2 를 모두 3 으로 바꿉니다. 앞쪽은 빈도 수집, 뒤쪽은 항목별 추천 단계라 둘 다 바꿔야 결과가 일치합니다.
  • '주차'·'번째' 같은 단위가 붙은 숫자도 키워드에서 빼기 — 1219줄 정규식 괄호 안 목록에 |번째 처럼 단위를 덧붙입니다(예: …|차년도|기준|번째)$). '주차'는 이미 들어 있으니 겹치지 않게 확인합니다.
  • 주황 버튼 색을 파랑으로 — 29줄 FC_ORANGE As Long = 39167 을 16742912 로 바꿉니다. Const 에는 RGB() 함수를 쓸 수 없어 숫자로 적는데, 값은 빨강 + 초록×256 + 파랑×65536(0x00BBGGRR, BGR 순서)이므로 RGB(0, 122, 255) = 0 + 122×256 + 255×65536 = 16742912 입니다. 참고로 현재 39167 은 RGB(255, 152, 0) 입니다.

고칠 때 주의

  • 주석에는 분석 키워드가 I~K열, 기준 키워드가 M~O열이라고 되어 있지만 실제 코드는 K열(161줄 "K")과 O열(543줄 "O")부터 씁니다. 기준폴더 이동은 622줄에서 P2(기준 키워드 표의 경로 칸)를 확인하므로, 표 위치를 옮기면 이 셀 주소도 함께 바꿔야 합니다.
  • 분석 직후 170줄 FC_ApplyFormatting 이 A4:I 범위의 배경을 지우고(1858줄) 줄무늬를 다시 칠하므로, 추천 단계에서 E열에 넣은 연두·노랑 표시는 처음 분석 결과에는 남지 않습니다. 색을 남기려면 서식 적용 뒤에 색칠하도록 순서를 바꿔야 합니다.
  • 파일 이동·이름 변경은 자동 백업이 없고 되돌릴 수 없습니다. 또 파일 내부 텍스트 검색 코드(1083~1206줄)는 kwArr 가 항상 비어 있어 지금은 실행되지 않으며, 살리면 Word 를 파일마다 새로 띄우므로 많이 느려질 수 있습니다.

06셀간격정리 셀정리하기

①모든 글자 1행 ②A4 가로 ③A4 세로 ④되돌리기 — 열 너비·행 높이 정리(#### 방지).

모듈 1개 · 448줄 · 리본 버튼 → 진입 프로시저 셀자동맞춤2 (modAutoFit)

modAutoFit 표준 모듈 · 448줄

셀간격정리 기능 전체(진입점, 대상 범위 결정, 한 줄 정리, A4 가로·세로 인쇄용 열 너비 배분, 백업 시트 저장·복원)를 담은 단일 모듈입니다.

소스 보기 (448줄)
심화과정: 소스 분석

리본 버튼이 셀자동맞춤2 를 부르면 대상 범위(2셀 이상 선택 범위 또는 사용 영역)를 정하고 선택 폼으로 네 가지 방식 중 하나를 고릅니다. 정리 전에 열 너비·행 높이·줄바꿈·셀에 맞춤·페이지 설정을 매우 숨김(VeryHidden) 백업 시트의 한 행에 문자열로 저장해 두고, '되돌리기' 를 고르면 그 문자열을 다시 풀어 원래 상태로 복원합니다. A4 인쇄용 정리는 열마다 한 줄 기준 너비와 숫자가 깨지지 않는 최소 너비를 측정한 뒤 인쇄 가능 폭 안에서 비례 배분합니다.

모듈 구성

  • modAutoFit — 셀간격정리 기능 전체(진입점, 대상 범위 결정, 한 줄 정리, A4 가로·세로 인쇄용 열 너비 배분, 백업 시트 저장·복원)를 담은 단일 모듈입니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modAutoFit 29~48줄(셀자동맞춤2)① 리본 진입과 방식 선택리본 버튼은 공통 허브 UI_Ribbon → UI_Run 을 거쳐 셀자동맞춤2 로 들어옵니다. 대상 범위를 구한 뒤 UI_Choose 로 4개 항목(한 줄로 / A4 가로 / A4 세로 / 되돌리기)을 보여 주고, 반환 번호에 따라 Select Case 로 각 처리 프로시저를 부릅니다. 취소하면 0이 돌아와 아무 것도 하지 않습니다.
  2. modAutoFit 51~65줄(AF_TargetRange)② 대상 범위 결정선택이 Range 이고 셀이 2개 이상이면 선택 범위를, 아니면 UsedRange 를 씁니다. 여러 영역을 선택했으면 첫 영역만 쓰고, 열·행 전체를 선택한 경우에는 사용 영역과의 Intersect 로 줄입니다. CountA 가 0이면 빈 범위로 보고 Nothing 을 돌려줍니다.
  3. modAutoFit 289~348줄(AF_Snapshot, AF_PutLong)③ 실행 전 상태 저장정리 전에 숨김 백업 시트(없으면 만들고 xlSheetVeryHidden 으로 숨김)에 시트 하나당 한 행을 기록합니다. A열 시트명, B열 저장 시각, C열 범위, D~H열 페이지 설정(방향·용지·Zoom·가로/세로 쪽수)을 넣고, I열부터 열 너비 열:너비;, 행 높이 행:높이;, 줄바꿈 셀 주소, 셀에 맞춤 셀 주소를 이어 씁니다. 셀 하나에 30000자(CHUNK)까지만 넣고 넘치면 다음 셀로 이어 쓰며, 각 묶음 끝에 | 셀을 둡니다. 같은 시트 기록이 이미 있으면 덮어쓰지 않아 '첫 실행 전' 상태가 유지됩니다.
  4. modAutoFit 68~88줄(AF_OneLine)④ 모든 글자 1행으로범위의 WrapText·ShrinkToFit 을 끄고 Columns.AutoFit 으로 열 너비를 내용에 맞춥니다. 너비가 MAX_COL_W(250)를 넘는 열은 250으로 자르고 개수를 세어 결과 메시지에 보여 준 뒤, Rows.AutoFit 으로 행 높이를 맞춥니다.
  5. modAutoFit 91~131줄(AF_FitPage)⑤ A4 인쇄용: 페이지 설정과 열 너비 측정용지를 xlPaperA4, 방향을 인수 orient 로 바꾸고, 가로면 A4 높이(841.9pt)·세로면 A4 폭(595.3pt)에서 좌우 여백을 빼 인쇄 가능 폭을 구합니다. AF_ApplyCellFormat 으로 글자 셀은 자동 줄바꿈, 숫자·날짜 셀은 셀에 맞춤으로 바꾼 다음, 측정을 위해 줄바꿈을 잠시 끄고 AutoFit 해 열마다 자연 너비 natW 와 숫자가 깨지지 않는 최소 너비 minW(AF_MinWidth)를 배열에 담습니다.
  6. modAutoFit 132~180줄(AF_FitPage)⑥ 인쇄 폭 안에서 열 너비 배분AF_MeasureUnit 이 마지막 열의 너비를 10만큼 바꿔 보며 '너비 1단위 = 몇 pt' 와 열당 고정 여백을 실측하고, 이를 이용해 인쇄 가능 폭을 너비 단위로 환산합니다. 자연 너비 합이 들어가면 그대로, 최소 너비 합조차 넘치면 최소 너비를 비율 축소(최소 2), 그 사이면 최소 너비를 보장하고 남는 폭을 (자연−최소)에 비례해 나눕니다. 끝으로 행 높이를 AutoFit 하고 FitToPagesWide = 1 로 가로 1쪽 맞춤을 안전장치로 겁니다.
  7. modAutoFit 362~448줄(AF_Restore, AF_GetLong)⑦ 되돌리기백업 시트에서 현재 시트 이름의 행을 찾고, AF_GetLong 으로 | 가 나올 때까지 셀을 이어 붙여 네 문자열을 복원합니다. 범위의 줄바꿈·셀에 맞춤을 모두 끈 뒤 기록된 셀만 다시 켜고, Split 으로 열:너비 쌍을 풀어 너비와 숨김(h 접미사)을 되돌리며 행 높이와 페이지 설정도 복원합니다. 사용한 기록 행은 지우고, 백업 시트가 비면 시트도 삭제합니다.

핵심 VBA 객체·함수

  • Range.Columns.AutoFit / Range.Rows.AutoFit — 열 너비와 행 높이를 셀 내용에 맞게 자동 조정합니다. 한 줄 정리와 자연 너비 측정에 쓰입니다.
  • Range.WrapText / Range.ShrinkToFit — 자동 줄바꿈과 '셀에 맞춤'(글자 축소) 서식 속성입니다. 글자 셀과 숫자 셀에 서로 다르게 적용됩니다.
  • Worksheet.PageSetup (.PaperSize, .Orientation, .Zoom, .FitToPagesWide, .FitToPagesTall) — 용지 크기·방향과 '한 페이지에 맞춤' 인쇄 설정을 바꾸고, 백업 시트에 원래 값을 기록해 복원합니다.
  • Range.ColumnWidth / Range.Width — ColumnWidth 는 문자 단위 너비, Width 는 pt 단위 실제 폭입니다. 두 값을 비교해 단위 환산 계수를 실측합니다.
  • Worksheet.Visible = xlSheetVeryHidden — 백업 시트를 시트 숨기기 취소 메뉴에도 나오지 않게 숨깁니다.
  • Intersect(rng, ws.UsedRange) — 열·행 전체를 선택했을 때 실제 데이터가 있는 영역만 남깁니다.
  • VarType(c.Value2) — 셀 값이 숫자·날짜·논리·오류 형식인지 판정해 숫자형(셀에 맞춤)과 글자형(줄바꿈)을 구분합니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 선택 폼(frmChoice)을 띄워 1~4번 정리 방식을 고르게 하고 번호를 반환
  • UI_Ribbon / UI_Run (modRibbonUI) — 리본 버튼 tag "셀자동맞춤2" 를 받아 이 프로시저를 호출하고 Excel 설정을 보관·복원

이렇게 고쳐 쓰세요

  • 한 줄 정리 때 열 너비 상한(현재 250) 바꾸기 — 16줄 Private Const MAX_COL_W As Single = 250 의 250 을 원하는 값(예: 100)으로 바꿉니다. 한 줄 정리(79줄)와 A4 정리의 자연 너비(125줄)에 함께 적용됩니다.
  • 글자 열의 최소 너비를 넓히기 — 15줄 MIN_TEXT_W As Single = 6 의 6 을 8 등으로 키웁니다. AF_MinWidth(217줄)가 이 값을 최소 너비의 출발점으로 씁니다.
  • 인쇄 시 세로도 1쪽에 맞추기 — 169줄 .FitToPagesTall = False 를 .FitToPagesTall = 1 로 바꿉니다. 행이 많으면 글자가 매우 작게 인쇄되니 주의합니다.
  • 숫자 셀 최소 너비 여유를 늘리기 — 223줄 L = Len(T) * (c.Font.Size / base) * 1.05 + 1.5 의 1.5 를 2.5 로 늘리면 숫자 열이 조금 더 넓어집니다.

고칠 때 주의

  • 백업 시트 이름 상수(11줄)를 바꾸면 이미 저장된 되돌리기 기록을 찾지 못합니다.
  • 되돌리기 기록은 시트별 1개이며 첫 실행 전 상태만 보관합니다(301줄). 두 번 정리한 뒤 되돌리면 첫 정리 이전으로 돌아갑니다.
  • 통합 문서 구조가 보호되어 있으면 백업 시트를 만들 수 없어 되돌리기 없이 진행됩니다(295-298줄).

07병합효과 셀정리하기

①적용: 실제 병합 없이 같은 값 구간의 가운데 한 칸만 표시 ②취소.

모듈 3개 · 195줄 · 리본 버튼 → 진입 프로시저 FakeMergeMenu (modFakeMergeMenu)

modFakeMergeMenu 표준 모듈 · 20줄

리본 tag "FakeMergeMenu" 의 진입점으로, 전·후 미리보기가 있는 선택 폼을 띄워 적용(Fake병합) 또는 취소(병합취소)로 보냅니다.

소스 보기 (20줄)
modFakeMerge 표준 모듈 · 145줄

병합효과 적용 본체(Fake병합)와 숨김 셀 표시형식 복원(FM_RestoreHidden), 배경색 선택 대화상자(PickBgColor)를 담고 있습니다.

소스 보기 (145줄)
modFakeMergeUndo 표준 모듈 · 30줄

선택 범위에서 숨김 표시형식·조건부서식·배경색을 걷어내 병합효과를 취소합니다.

소스 보기 (30줄)
심화과정: 소스 분석

셀을 실제로 병합하지 않고, 열마다 같은 값이 이어지는 구간을 찾아 가운데 한 칸만 보이게 하고 나머지 셀은 표시형식 ;;; 로 글자만 숨깁니다. 구간 사이의 가로 테두리는 R1C1 수식 조건부서식으로 지우므로 값은 셀마다 그대로 남아 정렬·필터·계산식이 계속 동작합니다. 숨기기 전 원래 표시형식은 셀의 ID 속성에 보관해 두었다가 취소 때 복원합니다.

모듈 구성

  • modFakeMergeMenu — 리본 tag "FakeMergeMenu" 의 진입점으로, 전·후 미리보기가 있는 선택 폼을 띄워 적용(Fake병합) 또는 취소(병합취소)로 보냅니다.
  • modFakeMerge — 병합효과 적용 본체(Fake병합)와 숨김 셀 표시형식 복원(FM_RestoreHidden), 배경색 선택 대화상자(PickBgColor)를 담고 있습니다.
  • modFakeMergeUndo — 선택 범위에서 숨김 표시형식·조건부서식·배경색을 걷어내 병합효과를 취소합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modFakeMergeMenu 8~20줄(FakeMergeMenu)① 메뉴 폼에서 적용/취소 선택UI_ChooseEx 에 항목 2개와 미리보기 사양 merge:after, merge:before 를 넘겨 전·후 모양을 그림으로 보여 줍니다. 체크 항목은 없으므로 Empty 와 더미 변수를 넘기고, 1이면 Fake병합, 2면 병합취소 를 부릅니다.
  2. modFakeMerge 7~30줄(Fake병합)② 범위 확인과 배경색 결정선택이 Range 가 아니거나 셀이 2개 미만이면 안내 후 끝냅니다. UI_Choose 로 '색상 직접 선택' 과 '기본 흰색' 중 하나를 고르게 하고, 직접 선택이면 PickBgColor 가 Excel 색 편집 대화상자를 띄웁니다. 흰색은 RGB(255, 255, 255) 입니다.
  3. modFakeMerge 32~47줄(Fake병합)③ 초기화와 테두리 숨김 조건부서식먼저 FM_RestoreHidden 으로 이전 병합효과의 숨김을 되돌리고, 기존 조건부서식을 지운 뒤 전체 테두리·가운데 정렬을 적용합니다. 이어서 =AND(RC<>"",RC=R[-1]C)(위 셀과 같으면 위쪽 선 없음)과 =AND(RC<>"",RC=R[1]C)(아래 셀과 같으면 아래쪽 선 없음) 두 규칙을 추가해 같은 값 구간이 한 칸처럼 보이게 합니다.
  4. modFakeMerge 49~72줄(Fake병합)④ 열별 같은 값 구간 찾기열 j 마다 위에서 아래로 내려가며 현재 셀과 다음 셀의 비교 문자열(FM_Val)이 같으면 countSame 을 늘립니다. 구간이 끝났을 때 길이가 2 이상이면 가운데 위치 (countSame - 1) \ 2 를 구해 구간에 배경색을 칠하고 FM_HideExcept 로 가운데 셀 외의 글자를 숨깁니다. 오류값은 주소를 붙여 서로 다르게 취급하므로 묶이지 않습니다.
  5. modFakeMerge 90~128줄(FM_HideExcept, FM_RestoreHidden)⑤ 표시형식 보관과 복원숨길 셀은 원래 NumberFormat 을 c.ID 에 적어 두고 ;;;(양수;음수;0;텍스트 모두 빈칸)로 바꿉니다. 복원할 때는 ID 에 보관한 형식을 쓰고, 없으면 위아래 50칸 안에서 같은 값이면서 숨겨지지 않은 이웃 셀의 형식을, 그것도 없으면 General 을 씁니다.
  6. modFakeMergeUndo 5~30줄(병합취소)⑥ 병합효과 취소한 셀만 선택했으면 CurrentRegion 으로 범위를 넓힙니다. 숨김 셀 수를 센 다음 FM_RestoreHidden 으로 표시형식을 되돌리고, 조건부서식 삭제, 전체 테두리 복원, Interior.ColorIndex = xlNone 으로 배경색을 없앱니다.

핵심 VBA 객체·함수

  • Range.FormatConditions.Add(Type:=xlExpression, Formula1:="=AND(RC<>"""",RC=R[-1]C)") — 수식형 조건부서식을 추가합니다. R1C1 표기라 범위의 모든 셀에 '바로 위 셀과 같으면' 조건이 상대적으로 적용됩니다.
  • FormatCondition.Borders(xlTop).LineStyle = xlNone — 조건이 참인 셀의 위쪽(또는 아래쪽) 테두리를 지워 같은 값 구간을 한 칸처럼 보이게 합니다.
  • Range.NumberFormat = ";;;" — 값은 그대로 두고 화면·인쇄에서 글자만 보이지 않게 하는 사용자 지정 표시형식입니다.
  • Range.ID — 셀에 붙일 수 있는 문자열 속성으로, 숨기기 전 원래 표시형식을 임시 보관하는 데 씁니다.
  • Application.Dialogs(xlDialogEditColor).Show(10, 255, 255, 255) — 통합 문서 팔레트 10번 색을 편집하는 색 대화상자를 띄웁니다. 고른 색을 읽은 뒤 팔레트를 원래 색으로 되돌립니다.
  • Range.CurrentRegion — 빈 행·열로 둘러싸인 연속 데이터 영역입니다. 취소 때 한 셀만 선택한 경우 범위를 넓히는 데 씁니다.

부르는 공통 함수

  • UI_ChooseEx (modRibbonUI) — 미리보기(merge:after / merge:before)가 있는 선택 폼
  • UI_Choose (modRibbonUI) — 배경색 방식 선택 폼
  • UI_DrawPreview (modUITheme) — frmChoice 가 미리보기 사양 문자열을 그림으로 그릴 때 사용

이렇게 고쳐 쓰세요

  • 기본 배경색을 흰색 대신 연한 회색으로 — modFakeMerge 29줄 bgColor = RGB(255, 255, 255) 를 RGB(242, 242, 242) 로 바꿉니다. VBA 의 RGB(빨,초,파) 함수는 내부적으로 BGR 순서 Long 값을 만들어 주므로 인수는 평소 RGB 순서대로 쓰면 됩니다.
  • 구간에서 가운데 대신 맨 위 셀만 보이게 — modFakeMerge 60줄 midOffset = (countSame - 1) \ 2 를 midOffset = 0 으로 바꿉니다.
  • 빈 셀도 같은 값으로 묶기 — modFakeMerge 56줄 If cur <> "" And cur = nxt Then 에서 cur <> "" And 를 지우고, 42·45줄 수식의 RC<>"""", 조건도 함께 빼야 테두리와 숨김이 일치합니다.

고칠 때 주의

  • 적용과 취소 모두 범위의 기존 조건부서식을 전부 삭제합니다(36줄, Undo 20줄). 다른 조건부서식이 있는 범위에는 주의합니다.
  • 취소는 배경색을 xlNone 으로 지우므로 병합효과 전부터 있던 배경색도 사라집니다.
  • 같은 값 비교는 열 방향(세로)만 합니다. 가로 방향 병합효과는 지원하지 않습니다.

08셀색표시 셀정리하기

①조건에 맞는 행만 색 ②색 지우기 ③~⑥ 교차형 파랑·노랑·핑크·연한녹색(폼 미리보기).

모듈 4개 · 377줄 · 리본 버튼 → 진입 프로시저 CellColorMenu (modCellColorMenu)

modCellColorMenu 표준 모듈 · 56줄

리본 tag "CellColorMenu" 의 진입점(메뉴 폼)과 '색 지우기'(CC_ClearColors)를 담당합니다.

소스 보기 (56줄)
modCellColorMark 표준 모듈 · 283줄

조건부서식으로 조건에 맞는 행에 색을 표시하는 셀색표시 본체와, 텍스트 조건 수식 생성·좌상단 셀 찾기·셀 서식 대화상자 색 선택 보조 함수를 담고 있습니다.

소스 보기 (283줄)
modAltRowBlue 표준 모듈 · 33줄

교차행 색칠 공용 루틴 AR_Stripe(짝수 행에 지정 색)와 예전 버튼용 진입점 짝수행연한파란색을 담고 있습니다.

소스 보기 (33줄)
modAltRowYellow 표준 모듈 · 5줄

예전 버튼용 진입점 짝수행연한노란색 하나뿐이며, AR_Stripe 에 연한 노랑을 넘겨 호출합니다.

소스 보기 (5줄)
심화과정: 소스 분석

리본의 CellColorMenu 가 미리보기가 있는 선택 폼으로 여섯 가지 작업(조건부 색 표시, 색 지우기, 교차형 4색)을 고르게 합니다. 조건부 색 표시는 기준열 주소를 '열 고정·행 상대'($B2 꼴)로 만들어 수식형 조건부서식을 추가하므로 조건에 맞는 행 전체가 칠해지고, 교차형은 짝수 번째 행의 Interior.Color 를 직접 칠합니다. 색 지우기는 범위의 채우기색과 조건부서식을 함께 제거합니다.

모듈 구성

  • modCellColorMenu — 리본 tag "CellColorMenu" 의 진입점(메뉴 폼)과 '색 지우기'(CC_ClearColors)를 담당합니다.
  • modCellColorMark — 조건부서식으로 조건에 맞는 행에 색을 표시하는 셀색표시 본체와, 텍스트 조건 수식 생성·좌상단 셀 찾기·셀 서식 대화상자 색 선택 보조 함수를 담고 있습니다.
  • modAltRowBlue — 교차행 색칠 공용 루틴 AR_Stripe(짝수 행에 지정 색)와 예전 버튼용 진입점 짝수행연한파란색을 담고 있습니다.
  • modAltRowYellow — 예전 버튼용 진입점 짝수행연한노란색 하나뿐이며, AR_Stripe 에 연한 노랑을 넘겨 호출합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modCellColorMenu 10~29줄(CellColorMenu)① 메뉴 폼과 분기UI_ChooseEx 에 6개 항목과 미리보기 사양 배열을 넘깁니다. 교차형 항목에는 stripe:DDEBF7 처럼 RRGGBB 16진 색을 주어 폼 오른쪽에 줄무늬 미리보기가 그려집니다. 선택 번호에 따라 셀색표시, CC_ClearColors, 또는 AR_Stripe RGB(...) 를 부릅니다.
  2. modCellColorMenu 32~56줄(CC_ClearColors)② 색 지우기한 셀만 선택했으면 CurrentRegion, 열·행 전체를 선택했으면 사용 영역과의 Intersect 로 범위를 정합니다. 확인 폼에서 '지우기' 를 고르면 조건부서식 수를 센 뒤 FormatConditions.Delete 와 Interior.ColorIndex = xlNone 으로 지웁니다. 글꼴·테두리·값은 건드리지 않습니다.
  3. modAltRowBlue 9~33줄(AR_Stripe)③ 교차형 색칠범위 결정 방식은 색 지우기와 같습니다. For i = 2 To rng.Rows.Count Step 2 로 범위 안의 짝수 번째 행만 골라 Interior.Color 를 칠하고 칠한 행 수를 알려 줍니다. 조건부서식이 아닌 직접 채우기라 정렬하면 색이 행을 따라 움직입니다.
  4. modCellColorMark 3~56줄(셀색표시)④ 조건부 색 표시: 처리 방식·범위·기준열먼저 기존 조건부서식을 지울지, 새 규칙을 1순위로 추가할지 고르게 하고 UI_ChoiceToMsg 로 vbYes/vbNo/vbCancel 로 바꿉니다. 적용 범위는 CurrentRegion 자동 선택 또는 Application.InputBox(Type:=8) 로 직접 드래그하게 하고, 기준열 셀도 같은 방식으로 받습니다. 기준 주소는 Address(RowAbsolute:=False, ColumnAbsolute:=True) 로 적용 범위 첫 행 기준 $열행 형태로 만듭니다.
  5. modCellColorMark 58~94줄(셀색표시)⑤ 조건 수식 만들기1·2번은 =ISODD(기준), =NOT(ISODD(기준)) 입니다. 3번은 UI_Input 으로 받은 문자열이 = 로 시작하면 그대로 수식으로, <·> 로 시작하면 기준 주소 뒤에 붙여 =$B2<10 처럼 만듭니다. 4번은 BuildTextConditionFormula 가 '기준 셀 값과 같음'(절대 주소 비교) 또는 '텍스트 포함'(IFERROR(ISNUMBER(SEARCH(...)),FALSE)) 수식을 만듭니다.
  6. modCellColorMark 96~139줄(셀색표시)⑥ 색 선택과 규칙 추가연한 노랑 RGB(255, 242, 204) 등 4색 중 고르거나, 5번이면 셀 서식 '패턴' 대화상자에서 직접 고릅니다. 처리 방식이 '모두 삭제' 면 기존 규칙을 지운 뒤 FormatConditions.Add(Type:=xlExpression) 로 규칙을 넣고 .Interior.Color 를 지정하며, '추가' 면 .SetFirstPriority 로 최우선 순위로 올립니다. 끝나면 범위 좌상단 셀로 화면을 되돌립니다.
  7. modCellColorMark 222~283줄(PickColorFromFormatCellsDialog_NoJump)⑦ 대화상자로 색 고르기(화면 점프 방지)시트 맨 끝 셀(XFD1048576)을 임시로 선택한 뒤 스크롤 위치를 되돌려 화면이 튀지 않게 하고, Application.Dialogs(xlDialogPatterns).Show 로 셀 서식 대화상자를 띄웁니다. 그 셀에 칠해진 색을 읽어 반환한 뒤 원래 값·채우기를 복원하고 범위 좌상단으로 이동합니다.

핵심 VBA 객체·함수

  • Range.FormatConditions.Add(Type:=xlExpression, Formula1:=formula1) — 수식이 TRUE 인 셀에 서식을 적용하는 조건부서식 규칙을 추가합니다. 기준열만 $ 로 고정해 행 전체에 같은 판단이 적용됩니다.
  • FormatCondition.SetFirstPriority — 새로 추가한 규칙을 조건부서식 우선순위 1번으로 올립니다.
  • Range.Address(RowAbsolute:=False, ColumnAbsolute:=True) — 열만 절대 참조인 주소(예: $B2)를 만들어 조건부서식 수식의 기준으로 씁니다.
  • Application.InputBox(Prompt, Title, Type:=8) — 사용자가 시트에서 마우스로 범위를 드래그해 Range 를 돌려받는 입력 상자입니다.
  • Application.Dialogs(xlDialogPatterns).Show — Excel 의 셀 서식 '채우기(패턴)' 대화상자를 띄웁니다. 확인하면 선택한 셀에 색이 적용됩니다.
  • Range.Interior.Color = RGB(221, 235, 247) — 셀 채우기 색을 직접 지정합니다. RGB 함수가 BGR 순서 Long 값을 만들어 줍니다.

부르는 공통 함수

  • UI_ChooseEx (modRibbonUI) — stripe:RRGGBB 미리보기가 있는 메뉴 폼
  • UI_Choose / UI_ChoiceToMsg (modRibbonUI) — 단계별 선택 폼과 선택 번호→vbYes/vbNo/vbCancel 변환
  • UI_Input (modRibbonUI) — 사용자 조건·포함 텍스트 입력 폼(frmInput)

이렇게 고쳐 쓰세요

  • 교차형 색을 짝수 행이 아니라 홀수 행에 칠하기 — modAltRowBlue 26줄 For i = 2 To rng.rows.Count Step 2 의 시작값 2 를 1 로 바꿉니다.
  • 교차형 파랑 색을 조금 더 진하게 — modCellColorMenu 24줄 RGB(221, 235, 247) 를 RGB(189, 215, 238) 로 바꾸고, 미리보기가 맞도록 20줄 stripe:DDEBF7 도 stripe:BDD7EE 로 고칩니다. 미리보기 문자열은 RRGGBB(빨-초-파) 순서의 16진수이고, RGB() 함수는 인수를 빨·초·파 순서로 받습니다(내부 Long 값은 BGR 순서).
  • 조건부 색 표시의 기본 노랑을 다른 색으로 — modCellColorMark 98줄 pickedColor = RGB(255, 242, 204) 의 세 숫자를 원하는 RGB 값으로 바꾸고, 97줄 항목 이름 "연한 노랑" 도 함께 고칩니다.

고칠 때 주의

  • 사용자 조건(3번)에서 = 로 시작하는 수식은 그대로 쓰이므로 기준 주소의 $·행 번호를 적용 범위 첫 행에 맞춰야 행마다 올바르게 판단됩니다.
  • 교차형 색은 직접 채우기라 '색 지우기' 로만 지워지고, 행을 정렬·삽입하면 줄무늬가 어긋납니다.
  • '조건부서식 모두 삭제' 를 고르면 적용 범위의 다른 규칙도 모두 사라집니다.

09테두리 스타일 셀정리하기

선 모양·굵기를 미리보기로 고르고 바깥·안쪽 테두리 적용.

모듈 1개 · 77줄 · 리본 버튼 → 진입 프로시저 테두리선스타일 (modBorderStyle)

modBorderStyle 표준 모듈 · 77줄

리본 tag "테두리선스타일" 진입점 하나로 범위 결정, 선택 폼, 조합 보정, 테두리 적용을 모두 처리합니다.

소스 보기 (77줄)
심화과정: 소스 분석

선택 범위(한 셀이면 연결 영역)에 대해 선 모양 미리보기가 있는 선택 폼 한 장으로 선 종류 6가지와 굵기 3단계를 함께 고르게 합니다. Excel 이 지원하지 않는 선 종류×굵기 조합은 자동으로 보정하고, 바깥 네 변과 안쪽 세로·가로선의 Borders 에 같은 LineStyle·Weight 를 적용합니다. 1열 또는 1행 범위에서는 안쪽 선을 건너뛰어 오류를 막습니다.

모듈 구성

  • modBorderStyle — 리본 tag "테두리선스타일" 진입점 하나로 범위 결정, 선택 폼, 조합 보정, 테두리 적용을 모두 처리합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modBorderStyle 6~13줄(테두리선스타일)① 대상 범위 결정리본 버튼은 UI_Ribbon → UI_Run 을 거쳐 이 프로시저로 들어옵니다. 선택이 Range 가 아니면 안내 후 끝내고, 셀 하나만 선택했으면 CurrentRegion 으로 표 전체를 대상으로 삼습니다.
  2. modBorderStyle 15~29줄(테두리선스타일)② 선 종류·굵기 선택 폼UI_ChooseEx 에 선 종류 6개, 미리보기 사양 line:solid~line:none, 체크 항목 얇게/중간/굵게(기본 1번)를 넘깁니다. 폼은 선택 번호를 반환하고 체크한 굵기 번호는 ByRef 인수 wt 로 돌려줍니다. 선택 번호를 xlContinuous·xlDot·xlDash·xlDashDot·xlDouble·xlLineStyleNone 상수로 바꿉니다.
  3. modBorderStyle 31~37줄(테두리선스타일)③ 테두리 지우기'테두리 없음' 을 고르면 rng.Borders.LineStyle = xlLineStyleNone 한 줄로 바깥·안쪽 선을 모두 지우고 끝냅니다.
  4. modBorderStyle 39~54줄(테두리선스타일)④ 굵기 변환과 조합 보정굵기 번호 2·3을 xlMedium·xlThick 로, 그 밖은 xlThin 으로 바꿉니다. 이중선은 굵기를 xlThick 으로 고정하고, 점선은 얇게만, 짧은 점선·점-실선은 굵게일 때 중간으로 낮추며, 보정했을 때는 안내 문구 fixMsg 를 남깁니다.
  5. modBorderStyle 56~77줄(테두리선스타일)⑤ 바깥·안쪽 선 적용Array(xlEdgeLeft, xlEdgeTop, xlEdgeBottom, xlEdgeRight) 를 돌며 네 변에 선 종류·굵기·자동 색(xlAutomatic)을 넣습니다. 열이 2개 이상일 때만 xlInsideVertical, 행이 2개 이상일 때만 xlInsideHorizontal 을 적용하고, 결과와 보정 안내를 메시지로 보여 줍니다.

핵심 VBA 객체·함수

  • Range.Borders(xlEdgeLeft | xlEdgeTop | xlEdgeBottom | xlEdgeRight) — 범위 바깥 네 변의 테두리 개체입니다.
  • Range.Borders(xlInsideVertical) / Range.Borders(xlInsideHorizontal) — 범위 안쪽 세로선·가로선입니다. 1열·1행 범위에서는 존재하지 않아 조건문으로 건너뜁니다.
  • Border.LineStyle = xlContinuous / xlDot / xlDash / xlDashDot / xlDouble — 선 종류를 지정합니다. xlLineStyleNone 은 선을 지웁니다.
  • Border.Weight = xlThin / xlMedium / xlThick — 선 굵기를 지정합니다. 선 종류에 따라 허용되는 굵기가 다릅니다.
  • Border.ColorIndex = xlAutomatic — 선 색을 자동(보통 검정)으로 맞춥니다.

부르는 공통 함수

  • UI_ChooseEx (modRibbonUI) — 선 모양 미리보기(line:…)와 굵기 체크 항목이 있는 선택 폼, 체크 값은 ByRef 로 반환
  • UI_DrawPreview (modUITheme) — line:solid 같은 사양 문자열로 폼 안에 선 모양을 그림

이렇게 고쳐 쓰세요

  • 테두리 색을 검정 대신 회색으로 — 61·66·71줄의 .ColorIndex = xlAutomatic 을 .Color = RGB(128, 128, 128) 로 바꿉니다. RGB() 는 빨·초·파 순서로 받아 BGR 순서 Long 값을 만듭니다.
  • 폼의 기본 굵기를 '중간' 으로 — 20줄 Array("얇게", "중간", "굵게"), 1, wt) 의 1 을 2 로 바꿉니다.
  • 바깥선만 적용하고 안쪽선은 그대로 두기 — 64-73줄의 두 If ... Borders(xlInside...) 블록을 삭제하거나 주석(') 처리합니다.

고칠 때 주의

  • 선 종류 목록(18줄)과 미리보기 배열(19줄), Select Case 번호(22-29줄)는 순서가 같아야 합니다. 항목을 추가하면 세 곳을 함께 고칩니다.
  • '테두리 없음' 은 범위의 기존 테두리를 모두 지웁니다.

10빈칸삭제 셀정리하기

선택 열의 빈 셀 행 삭제(자동 백업).

모듈 1개 · 82줄 · 리본 버튼 → 진입 프로시저 b빈칸삭제 (modDeleteBlankRows)

modDeleteBlankRows 표준 모듈 · 82줄

리본 tag "b빈칸삭제" 진입점 하나로 기준 셀 입력, 역순 반복 삭제, 결과 안내를 처리합니다.

소스 보기 (82줄)
심화과정: 소스 분석

사용자가 고른 기준 셀의 열에서, 그 셀 행부터 열의 마지막 데이터 행까지 아래에서 위로 거꾸로 훑으며 기준 열이 비어 있는 행을 삭제합니다. 행 전체가 비어 있으면 바로 지우고, 기준 열만 비고 다른 열에 데이터가 있으면 처음 한 번만 '그래도 삭제 / 유지' 를 묻고 그 답을 끝까지 적용합니다. 실행 직전에는 공통 허브(UI_Run)가 활성 시트를 숨김 백업 시트로 복사해 둡니다.

모듈 구성

  • modDeleteBlankRows — 리본 tag "b빈칸삭제" 진입점 하나로 기준 셀 입력, 역순 반복 삭제, 결과 안내를 처리합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modRibbonUI 54 (UI_Run) → modDeleteBlankRows 1-22 (b빈칸삭제) ① 자동 백업 후 기준 셀 받기UI_Run 은 이 기능을 '삭제 계열' 로 분류해(UI_IsDestructive) 실행 전에 활성 시트를 숨김 백업 시트로 복사합니다. 이어서 Application.InputBox(Type:=8) 로 기준 셀을 마우스로 고르게 하고, 취소하면 On Error Resume Next 덕분에 변수가 Nothing 으로 남아 안내 후 끝냅니다.
  2. modDeleteBlankRows 24~36줄(b빈칸삭제)② 기준 열과 검사 구간 결정여러 셀을 골라도 Cells(1, 1) 첫 셀만 기준으로 삼습니다. 그 셀의 열 번호와 행 번호를 시작점으로, Cells(Rows.Count, 열).End(xlUp).Row 로 그 열의 마지막 데이터 행을 끝점으로 정합니다. 끝점이 시작점보다 위면 할 일이 없으므로 끝냅니다.
  3. modDeleteBlankRows 38~69줄(b빈칸삭제)③ 아래에서 위로 빈 행 삭제For i = lastRow To startRow Step -1 로 역순 반복해 행을 지워도 아직 검사하지 않은 행 번호가 밀리지 않게 합니다. 기준 셀이 오류값이 아니고 Trim 후 길이가 0이면 빈칸으로 봅니다. CountA(ws.Rows(i)) 가 0이면 바로 삭제하고, 다른 데이터가 있으면 처음 한 번 UI_Choose 로 물어 vbYes(삭제)/vbNo(유지)/vbCancel(중단)을 정합니다.
  4. modDeleteBlankRows 71~82줄(b빈칸삭제)④ 마무리와 결과 안내화면 갱신을 다시 켜고, 중단하지 않았다면 삭제한 행 수와 유지한 행 수를 보여 주며 리본의 '백업 시트 복원' 으로 되돌릴 수 있음을 안내합니다.

핵심 VBA 객체·함수

  • Application.InputBox(prompt, title, Type:=8) — 시트에서 셀을 마우스로 선택해 Range 로 받는 입력 상자입니다. 취소하면 False 가 돌아와 Set 이 실패합니다.
  • Cells(Rows.Count, col).End(xlUp).Row — 열의 맨 아래에서 위로 올라가 마지막으로 데이터가 있는 행 번호를 구합니다.
  • Application.WorksheetFunction.CountA(ws.Rows(i)) — 행 전체에서 비어 있지 않은 셀 수를 셉니다. 0이면 완전히 빈 행입니다.
  • ws.Rows(i).Delete — 행 전체를 삭제하고 아래 행을 위로 올립니다.
  • IsError(value) — #N/A 같은 오류값을 빈칸으로 잘못 판단하거나 Trim 에서 형식 오류가 나는 것을 막습니다.

부르는 공통 함수

  • UI_Run / UI_MakeBackup (modRibbonUI) — 실행 직전 활성 시트를 '백업_' 숨김 시트로 복사(최근 3개 보관)
  • UI_Choose / UI_ChoiceToMsg (modRibbonUI) — 다른 데이터가 있는 행 처리 방법 선택과 vbYes/vbNo/vbCancel 변환
  • UI_RestoreBackup (modRibbonUI) — 결과 메시지가 안내하는 되돌리기 기능

이렇게 고쳐 쓰세요

  • 공백만 있는 셀은 빈칸으로 보지 않기 — 46줄 Len(Trim$(CStr(ws.cells(i, targetColNum).value))) = 0 에서 Trim$(...) 를 빼고 Len(CStr(ws.cells(i, targetColNum).value)) = 0 으로 바꿉니다.
  • 묻지 않고 항상 '완전히 빈 행만' 삭제 — 50-53줄의 질문 블록을 지우고 40줄 아래에 userChoice = vbNo 한 줄을 추가합니다. 76줄의 완료 메시지 조건은 그대로 둬도 됩니다.
  • 기준 셀 행은 검사에서 빼기(제목 행 보호) — 43줄 For i = lastRow To startRow Step -1 의 startRow 를 startRow + 1 로 바꿉니다.

고칠 때 주의

  • 삭제는 Excel 실행 취소(Ctrl+Z)로 되돌릴 수 없습니다. 되돌리기는 자동 백업 시트에 의존하므로 리본 버튼으로 실행해야 백업이 만들어집니다.
  • 검사 구간의 끝은 기준 열의 마지막 데이터 행이라, 기준 열이 비어 있는 맨 아래 행들은 검사하지 않습니다.
  • 첫 질문의 답이 이후 모든 행에 적용됩니다.

11중복셀값제거 셀정리하기

선택 열에서 반복되는 제목 줄 등 중복 값 행 삭제(자동 백업).

모듈 1개 · 107줄 · 리본 버튼 → 진입 프로시저 c중복셀값제거 (modRemoveDupRows)

modRemoveDupRows 표준 모듈 · 107줄

리본 tag "c중복셀값제거" 진입점 하나로 기준 셀 입력, 확인, 시트 보호·필터 해제, 역순 삭제를 처리합니다.

소스 보기 (107줄)
심화과정: 소스 분석

사용자가 고른 기준 셀의 값과 같은 값을 가진 같은 열의 다른 행을 모두 삭제하고, 기준 셀의 행 하나만 남깁니다. 비교는 앞뒤 공백을 뺀 문자열로 하며, 행 번호가 밀리지 않도록 열의 마지막 데이터 행부터 1행까지 거꾸로 훑습니다. 실행 직전에는 공통 허브(UI_Run)가 활성 시트를 숨김 백업 시트로 복사합니다.

모듈 구성

  • modRemoveDupRows — 리본 tag "c중복셀값제거" 진입점 하나로 기준 셀 입력, 확인, 시트 보호·필터 해제, 역순 삭제를 처리합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modRibbonUI 54 (UI_Run) → modRemoveDupRows 1-36 (c중복셀값제거) ① 자동 백업 후 기준 셀 받기UI_Run 이 이 기능을 삭제 계열로 보고 활성 시트를 숨김 백업 시트로 먼저 복사합니다. Application.InputBox(Type:=8) 로 기준 셀을 받고, 여러 셀을 골랐으면 첫 셀만 씁니다. 기준 셀이 오류값이거나 비어 있으면 안내 후 끝냅니다. 비교에 쓸 값 keyword 와 남길 셀 주소 selectedAddress 를 저장합니다.
  2. modRemoveDupRows 38~54줄(c중복셀값제거)② 확인과 실행 준비UI_Choose 로 '삭제 실행 / 취소' 를 묻습니다. 실행하면 화면 갱신을 끄고 계산을 수동(xlCalculationManual)으로 바꾼 뒤, 비밀번호 없는 시트 보호는 Unprotect 로 풀고 자동 필터가 켜져 있으면 끕니다(필터가 걸린 상태에서는 숨은 행 삭제가 꼬일 수 있기 때문입니다).
  3. modRemoveDupRows 58~89줄(c중복셀값제거)③ 아래에서 위로 같은 값 행 삭제For i = lastRow To 1 Step -1 로 기준 열을 거꾸로 훑습니다. 현재 셀 주소가 기준 셀과 다르고, 오류값이 아니며, Trim(CStr(...)) 로 비교한 값이 같으면 EntireRow.Delete 로 행을 지웁니다. 삭제 오류는 Err 를 확인해 직접 실행 창에 기록하고 건너뜁니다.
  4. modRemoveDupRows 91~107줄(c중복셀값제거)④ 마무리와 결과 안내계산을 자동으로 되돌리고 화면 갱신을 켭니다. 시트 재보호(ws.Protect)는 주석으로 남아 있어 실행되지 않습니다. 삭제한 행 수와 '백업 시트 복원' 안내를 보여 주거나, 지운 행이 없으면 그 사실을 알립니다.

핵심 VBA 객체·함수

  • Application.InputBox(prompt, title, Type:=8) — 시트에서 마우스로 기준 셀을 골라 Range 로 받습니다.
  • Application.Calculation = xlCalculationManual — 행을 지울 때마다 수식이 다시 계산되지 않게 잠시 수동 계산으로 바꿉니다.
  • ws.Unprotect / ws.AutoFilterMode = False — 비밀번호 없는 시트 보호를 풀고 자동 필터를 해제해 행 삭제가 막히지 않게 합니다.
  • ws.Rows(i).EntireRow.Delete — 행 전체를 삭제합니다.
  • Range.Address — 기준 셀 주소와 현재 셀 주소를 비교해 기준 행을 삭제 대상에서 제외합니다.

부르는 공통 함수

  • UI_Run / UI_MakeBackup (modRibbonUI) — 실행 직전 활성 시트를 숨김 백업 시트로 복사
  • UI_Choose (modRibbonUI) — 삭제 확인 폼
  • UI_RestoreBackup (modRibbonUI) — 결과 메시지가 안내하는 되돌리기 기능

이렇게 고쳐 쓰세요

  • 대소문자를 구분하지 않고 비교하기 — 72줄 If Trim(CStr(currentCell.value)) = Trim(CStr(keyword)) Then 의 양쪽을 UCase(Trim(CStr(...))) 로 감쌉니다.
  • 기준 셀 아래쪽 행만 삭제(위쪽은 유지) — 64줄 For i = lastRow To 1 Step -1 의 1 을 targetCell.row + 1 로 바꿉니다.
  • 작업 후 시트 다시 보호하기 — 97줄 ' ws.Protect 앞의 작은따옴표를 지웁니다. 원래 보호되지 않았던 시트도 보호되므로 필요할 때만 씁니다.

고칠 때 주의

  • 비교 범위는 기준 열 1행부터 마지막 데이터 행까지 전체라 표 위쪽의 같은 값(예: 제목)도 지워질 수 있습니다.
  • 중간에 오류가 나면 계산 방식이 수동으로 남을 수 있지만, 리본 허브 UI_Run 이 종료 시 원래 계산 방식을 복원합니다.
  • 행 삭제는 Ctrl+Z 로 되돌릴 수 없어 자동 백업 시트에 의존합니다.

12한글(HWPX) 계산확인 HWPX활용기능

①계산 내용 확인: 한글 산출 근거 글을 줄마다 계산해 합계·예산액 대조 ②표 계산 확인: 한글 표를 복사하면 계산식·금액 열을 자동 인식.

모듈 2개 · 1,424줄 · 리본 버튼 → 진입 프로시저 HwpCalcMenu (modHwpCalcClipboard)

modHwpCalcClipboard 표준 모듈 · 709줄

리본 tag "HwpCalcMenu" 진입점(한글계산확인)과 산출 근거 글 계산(한글계산1차), 클립보드 읽기, 금액·단위 정규식 파싱 보조 함수를 담고 있습니다.

소스 보기 (709줄)
modTableCalc 표준 모듈 · 715줄

한글 표를 붙여 넣어 계산식 열·금액 열을 자동 인식하고(TC_DetectColumns), 두 줄 칸을 합친 뒤(TC_NormalizeRows) 행별 재계산·차이·비율·부분합·총합계를 만드는 표계산 본체입니다.

소스 보기 (715줄)
심화과정: 소스 분석

한글 문서에서 복사(Ctrl+C)한 내용을 클립보드에서 읽어 새 통합 문서에서 다시 계산하고, 원문에 적힌 금액과 다르면 색과 비고로 표시합니다. '계산 내용 확인' 은 산출 근거 글을 줄 단위로 정규식 파싱해 Application.Evaluate 로 곱셈·나눗셈을 계산하고 들여쓰기로 상·하위 항목 합계를 대조하며, '표 계산 확인' 은 붙여 넣은 표에서 계산식 열과 금액 열을 자동 인식해 재배치한 뒤 행별 재계산·부분합·총합계를 만듭니다. 끝으로 결과 범위를 한글에 바로 붙일 수 있는 HTML 표 형식으로 클립보드에 올립니다.

모듈 구성

  • modHwpCalcClipboard — 리본 tag "HwpCalcMenu" 진입점(한글계산확인)과 산출 근거 글 계산(한글계산1차), 클립보드 읽기, 금액·단위 정규식 파싱 보조 함수를 담고 있습니다.
  • modTableCalc — 한글 표를 붙여 넣어 계산식 열·금액 열을 자동 인식하고(TC_DetectColumns), 두 줄 칸을 합친 뒤(TC_NormalizeRows) 행별 재계산·차이·비율·부분합·총합계를 만드는 표계산 본체입니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modHwpCalcClipboard 11~50줄(한글계산확인)① 메뉴 선택, 새 문서, 결과 복사UI_Choose 로 '계산 내용 확인' 과 '표 계산 확인' 중 하나를 고르면 Workbooks.Add 로 새 통합 문서를 만들고, 개별 완료 메시지를 끄는 HCM_Quiet 를 켠 채 한글계산1차 또는 표계산 을 부릅니다. 끝나면 결과 시트의 A2:D(또는 A1:G) 범위를 HC_CopyRangeAsTable(rng, nR, nC, True, 10) 으로 색 유지·10pt 표 형태로 클립보드에 올립니다.
  2. modHwpCalcClipboard 62~130줄, 427-438 (한글계산1차, GetClipboardText)② 클립보드 글 읽기와 결과 시트 준비CreateObject("htmlfile") 의 clipboardData.GetData("Text") 로 클립보드 글을 읽고, 막힌 환경이면 MSForms DataObject 로 다시 읽습니다. 비어 있으면 시트를 건드리지 않고 끝냅니다. '한글계산' 시트를 재사용하거나 만든 뒤 계산을 수동으로 바꾸고, 머리글(No./원문/계산값/비고)을 하늘색 RGB(199, 230, 255) 으로 꾸밉니다. 줄바꿈을 vbLf 로 통일해 줄 배열로 나눕니다.
  3. modHwpCalcClipboard 132~223줄(한글계산1차)③ 줄마다 금액 계산과 원문 대조제외 키워드 줄은 건너뛰고 StripPrefixMarkers 가 '1)', '가.' 같은 앞 번호를 정규식으로 지웁니다. = 기준으로 왼쪽(계산식)과 오른쪽(원문 결과)을 나눠, 곱하기·나누기 기호가 있으면 EvaluateFormulaInText(숫자·연산자만 남겨 Application.Evaluate)와 ApplyUnitFromLine(천원·백만원 배율)으로, 없으면 SumMoneyValuesWon 으로 단위 붙은 금액을 합산합니다. 오른쪽 금액과 다르면 B:C 를 연분홍으로 칠하고 비고에 '불일치' 를 적습니다. 단위 없는 숫자, 1000원 미만 금액도 비고로 알립니다.
  4. modHwpCalcClipboard 227~351줄(한글계산1차)④ 들여쓰기로 상·하위 합계 대조와 요약예산액·총액·합계·소계 줄은 합산에서 뺍니다. 원문 앞 공백 수(GetIndentLevel)가 다음 줄보다 얕으면 상위 항목으로 보고, 더 깊게 들여쓴 하위 줄 합과 같으면 연녹색으로 칠해 '하위 항목과 일치' 로 표시하고 총계에서 빼 이중 합산을 막습니다. 아래에 '합계(계산)', '예산액/총액', '차이' 행을 만들고, UI_Choose 로 원/천원 단위를 고르게 해 천원이면 값을 1000으로 나눠 #,##0"천원" 표시형식을 붙입니다.
  5. modTableCalc 13~68줄, 520-545 (표계산, TC_ClipboardHasText)⑤ 표 붙여넣기와 열 자동 인식클립보드에 글이 있는지 먼저 확인하고 '표계산' 시트를 비운 뒤 A1:G1 에 No/계산1/결과1/계산2/결과2/비고1/비고2 머리글을 씁니다. ws.Paste Destination:=ws.Range("B2") 로 한글 표를 그대로 붙여 넣고, TC_DetectColumns 와 TC_NormalizeRows 로 정리합니다.
  6. modTableCalc 600~709줄(TC_DetectColumns, TC_FindPair, TC_IsNumText, TC_LooksExpr)⑥ 계산식 열·금액 열 판별과 재배치병합을 풀고 열마다 비어 있지 않은 칸 중 숫자(쉼표·△·단위 허용) 비율이 60% 이상이면 num, 연산자나 '원' 이 든 글이 30% 이상이면 expr 로 분류합니다. '계산식 열 바로 오른쪽이 숫자 열' 인 첫 쌍과 두 번째 쌍을 찾아 B~E 로 옮기고 나머지 열(항목명·차이 등)은 지웁니다. 결과1 칸이 글자인 맨 위 행은 머리글로 보고 최대 3행까지 삭제합니다. TC_NormalizeRows 는 결과 칸이 둘 다 빈 행을 앞 행의 계산식 뒤에 이어 붙이고 삭제합니다.
  7. modTableCalc 93~239줄(표계산)⑦ 행별 재계산·차이·비율행마다 D열 계산식을 TC_CleanExpr 로 숫자·연산자만 남기고(×→*, ÷→/) Application.Evaluate 로 계산해 E열에 넣습니다. 원문 결과2와 다르면 글자를 빨강(vbRed)으로 바꾸고, 계산값이 원문의 500~2000배이면 '산출은 원, 예산은 천원' 표로 보고 1000으로 나눕니다. F열에 결과1−결과2, G열에 F÷E×100 을 넣고, 음수는 △ 기호(ChrW(9651)), 0은 ;;; 로 숨기는 표시형식을 씁니다. B열이 '부분합' 인 행은 CalculateAndSetSubtotal 로 구간 합을 채웁니다.
  8. modTableCalc 241~276줄, 375-518 (표계산, CalculateAndSetGrandTotal)⑧ 마지막 부분합·총합계와 마무리마지막 구간이 부분합으로 끝나지 않았으면 마지막 행 다음에 부분합을 추가합니다. 부분합 행은 '배경색이 RGB(220, 230, 241) 이고 B열이 빈 행' 으로 판별해, 일반 행만 더한 '총합계'(노랑)와 부분합만 더한 '부분합 총합'(연주황)을 두 칸 아래에 만듭니다. 열 너비를 AutoFit 하되 40을 넘지 않게 하고, 메뉴에서 부르지 않았을 때만 완료 메시지와 열 인식 결과를 보여 줍니다.

핵심 VBA 객체·함수

  • CreateObject("htmlfile").parentWindow.clipboardData.GetData("Text") — 참조 추가 없이 클립보드의 일반 텍스트를 읽는 방법입니다. 실패하면 MSForms DataObject 의 GetFromClipboard·GetText 로 대신 읽습니다.
  • CreateObject("VBScript.RegExp") (.Pattern, .Global, .Execute, .SubMatches) — "([0-9][0-9,\.]*)\s*(백만원|천원|원)" 같은 정규식으로 금액과 단위를 찾아 원 단위로 환산합니다.
  • Application.Evaluate(tempExpr) — "3*12000" 같은 문자열 수식을 Excel 수식처럼 계산해 숫자를 돌려줍니다.
  • Worksheet.Paste Destination:=ws.Range("B2") — 클립보드의 한글 표를 B2 부터 셀 구조 그대로 붙여 넣습니다.
  • Range.UnMerge — 한글 표에서 따라온 병합 셀을 풀어 행·열 분석이 가능하게 합니다.
  • Range.NumberFormat = "#,##0_ ;" & ChrW(9651) & "#,##0;;" — 양수는 천 단위 쉼표, 음수는 △ 기호, 0은 빈칸으로 보이게 하는 사용자 지정 표시형식입니다.
  • Range.Value2 (2차원 배열 읽기·쓰기) — 열 자동 인식에서 붙여 넣은 표 전체를 배열로 한 번에 읽고, 재배치한 배열을 한 번에 다시 씁니다.

부르는 공통 함수

  • UI_Choose / UI_ChoiceToMsg (modRibbonUI) — 계산 방식 선택, 원/천원 단위 선택
  • HC_CopyRangeAsTable (modHwpCopy) — 결과 범위를 색 유지 HTML 표로 클립보드에 복사
  • UI_Run (modRibbonUI) — 리본 tag "HwpCalcMenu" 를 받아 한글계산확인을 호출

이렇게 고쳐 쓰세요

  • 불일치 줄 강조색을 노랑으로 — modHwpCalcClipboard 202줄 Interior.color = RGB(255, 230, 230) 을 RGB(255, 255, 0) 으로 바꿉니다. VBA RGB(빨,초,파) 는 BGR 순서 Long 값을 만들어 주므로 인수는 RGB 순서로 씁니다.
  • 계산식에서 인식하는 수량 단위 추가(예: '켤레') — modHwpCalcClipboard 615줄과 669줄 정규식 괄호 안 목록 끝 |점|팀) 을 |점|팀|켤레) 로 두 곳 모두 고칩니다. 한 곳만 고치면 '수량단위 확인' 비고가 계속 붙습니다.
  • 표계산 결과 열 너비 상한 넓히기 — modTableCalc 10줄 MAX_COLUMN_WIDTH As Double = 40 의 40 을 60 등으로 바꿉니다.
  • 천원 표 자동 환산 범위 조정 — modTableCalc 139줄 > 500 And ... < 2000 의 두 숫자를 바꿉니다. 이 범위 밖이면 원 단위 그대로 비교합니다.

고칠 때 주의

  • 부분합 행 판별은 A열 배경색 RGB(220, 230, 241) 에 의존합니다(295·393줄). 157·312줄의 부분합 색을 바꾸면 판별 색도 함께 바꿔야 이중 합산이 생기지 않습니다.
  • 계산식 문자열의 소문자·대문자 x 도 곱하기로 바뀌므로 'x' 가 든 항목명은 계산을 어지럽힐 수 있습니다.
  • 모든 결과는 새 통합 문서에 만들어지므로 원본 문서는 바뀌지 않지만, 저장하지 않으면 결과도 사라집니다.

13한글로 복사 HWPX활용기능

①글자만(탭 구분) ②양식 포함(얇은 실선 표, 글자 길이에 맞춘 열 너비) → 한글 Ctrl+V.

모듈 1개 · 408줄 · 리본 버튼 → 진입 프로시저 HwpCopyMenu (modHwpCopy)

modHwpCopy 표준 모듈 · 408줄

리본 tag "HwpCopyMenu" 메뉴와 글자만 복사(HwpCopyText), 양식 포함 복사(HwpCopyTable), HTML 표 생성(HC_BuildHtml), 클립보드 API 호출(HC_SetClipboardHtml)을 모두 담은 모듈입니다. HC_CopyRangeAsTable 은 한글 계산확인 기능도 결과 복사에 재사용합니다.

소스 보기 (408줄)
심화과정: 소스 분석

선택 범위(한 셀이면 연결 영역)의 가장자리 빈 행·열을 잘라낸 뒤, '글자만' 은 탭 구분 텍스트를 DataObject 로 클립보드에 올리고, '양식 포함' 은 VBA 로 HTML <table> 문자열을 직접 만들어 Windows API 로 클립보드에 'HTML Format'(UTF-8) + 유니코드 텍스트를 함께 올립니다. Excel 복사 기능을 쓰지 않으므로 원본 서식(채우기색·조건부서식)이 따라가지 않고, 한글 문서 본문 폭(150mm)에 맞춘 열 너비·정렬·굵게·병합(colspan/rowspan)만 반영된 깔끔한 표가 붙습니다.

모듈 구성

  • modHwpCopy — 리본 tag "HwpCopyMenu" 메뉴와 글자만 복사(HwpCopyText), 양식 포함 복사(HwpCopyTable), HTML 표 생성(HC_BuildHtml), 클립보드 API 호출(HC_SetClipboardHtml)을 모두 담은 모듈입니다. HC_CopyRangeAsTable 은 한글 계산확인 기능도 결과 복사에 재사용합니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modHwpCopy 81~95줄(HwpCopyMenu)① 메뉴에서 복사 방식 선택선택이 Range 가 아니면 안내 후 끝냅니다. UI_Choose 로 '글자만 복사' 와 '양식 포함 복사' 중 하나를 고르게 하고, 한 셀만 선택했으면 안내문에 '연결된 표 전체' 라고 알려 줍니다. 선택 번호에 따라 HwpCopyText Nothing 또는 HwpCopyTable Nothing 을 부릅니다.
  2. modHwpCopy 353~408줄(HC_TargetRange, HC_TrimEmpty, HC_CellText)② 대상 범위 정리와 셀 글자 읽기한 셀이면 CurrentRegion, 여러 영역이면 첫 영역, 열·행 전체면 사용 영역과 교차한 범위를 씁니다. HC_TrimEmpty 는 위·아래·왼쪽·오른쪽 가장자리에서 CountA 가 0인 행·열을 깎아 냅니다. 셀 글자는 화면 표시값 c.Text 를 쓰되(표시형식 유지), 오류값은 빈칸으로, 셀 안 줄바꿈은 공백으로 바꿉니다.
  3. modHwpCopy 33~58줄(HwpCopyText)③ 글자만 복사행마다 셀 글자를 vbTab 으로 이어 붙이고, 탭을 빼면 빈 문자열인 행은 건너뜁니다. CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}") 로 MSForms DataObject 를 만들어 SetText·PutInClipboard 로 클립보드에 올립니다.
  4. modHwpCopy 114~180줄(HC_BuildHtml)④ 양식 포함: 열 너비 계산빈 열은 표시하지 않습니다. 열마다 가장 긴 글자의 폭을 '한글 2·그 외 1' 단위(HC_TextUnits)로 재서 3~44 사이로 제한하고, 단위 × 2.1 × 글꼴배율 + 6 mm 로 바꿉니다. 합이 150mm 를 넘으면 숫자 셀이 60% 이상인 열은 그대로 두고 글 열만 비례 축소(최소 14mm)하며, 그래도 넘치면 전체를 150mm 에 맞춰 줄입니다.
  5. modHwpCopy 181~228줄(HC_BuildHtml)⑤ 양식 포함: HTML 표 만들기<table border="1" ...> 에 행마다 <tr>, 셀마다 <td> 를 붙입니다. 병합 셀은 첫 셀에서 colspan·rowspan 을 넣고 나머지 셀은 건너뜁니다. 정렬은 셀 가로 맞춤을 따르고 '일반' 이면 숫자는 오른쪽, 글자는 왼쪽입니다. 너비는 width 속성(mm×3.78 픽셀)과 style 의 mm 로 함께 지정하고, 굵게·글꼴 크기·숫자 줄바꿈 금지(white-space:nowrap)를 style 에 넣습니다. 동시에 탭 구분 평문(plain)도 만듭니다.
  6. modHwpCopy 277~322줄(HC_SetClipboardHtml)⑥ CF_HTML 형식으로 클립보드에 올리기Windows 의 HTML 클립보드 형식은 앞에 StartHTML/EndHTML/StartFragment/EndFragment 바이트 위치 헤더가 필요해, 헤더를 자리만 잡아 길이를 잰 뒤 UTF-8 바이트 수(HC_Utf8Len)로 위치를 계산해 다시 만듭니다. OpenClipboard 를 최대 10번(50ms 간격) 시도하고, GlobalAlloc·GlobalLock·CopyMemory 로 메모리에 담아 SetClipboardData 로 'HTML Format' 과 CF_UNICODETEXT(13) 두 형식을 올립니다.
  7. modHwpCopy 98~108줄, 243-265 (HC_CopyRangeAsTable, HC_FillHex, HC_HexBgr)⑦ 다른 기능용 공개 함수와 색 변환HC_CopyRangeAsTable 은 다른 모듈이 범위를 같은 방식으로 복사할 때 쓰는 공개 함수로, keepColors 가 참이면 채우기색·글자색도 HTML 에 넣습니다. Excel 의 Color 값은 BGR 순서(0x00BBGGRR) Long 이라 HC_HexBgr 가 하위 바이트(R)부터 꺼내 HTML 용 RRGGBB 로 바꿉니다. 흰 채우기(16777215)와 검정 글자(0)는 생략합니다.

핵심 VBA 객체·함수

  • CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}").SetText / .PutInClipboard — 참조 추가 없이 MSForms.DataObject 를 만들어 일반 텍스트를 클립보드에 올립니다.
  • RegisterClipboardFormat("HTML Format") — Windows 에 등록된 HTML 클립보드 형식 번호를 얻습니다. 한글은 이 형식을 표로 붙여 넣습니다.
  • OpenClipboard / EmptyClipboard / SetClipboardData / CloseClipboard (user32) — 클립보드를 열어 비우고, 형식별 메모리 핸들을 넘긴 뒤 닫는 Windows API 입니다. 64비트용 PtrSafe·LongPtr 선언과 32비트 선언을 #If VBA7 로 나눕니다.
  • GlobalAlloc / GlobalLock / GlobalUnlock / RtlMoveMemory (kernel32) — 클립보드에 넘길 이동 가능 전역 메모리를 잡고 바이트 배열·문자열 내용을 복사합니다.
  • CreateObject("ADODB.Stream") (Charset = "utf-8") — VBA 문자열(UTF-16)을 UTF-8 바이트 배열로 바꿉니다. 앞의 BOM 3바이트는 건너뜁니다.
  • Range.MergeArea / Range.MergeCells — 병합 여부와 병합 영역 크기를 읽어 HTML 의 colspan/rowspan 으로 옮깁니다.
  • Range.Text — 표시형식이 적용된 화면 글자(예: 1,000 / 2026-01-01)를 읽어 그대로 복사합니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 글자만/양식 포함 선택 폼
  • UI_Ribbon / UI_Run (modRibbonUI) — 리본 tag "HwpCopyMenu" 를 받아 이 메뉴를 호출

이렇게 고쳐 쓰세요

  • 붙여 넣을 표의 기본 글꼴을 바꾸기 — 181줄과 211줄의 font-family:'맑은 고딕' 두 곳을 원하는 글꼴 이름(예: '함초롬바탕')으로 바꿉니다.
  • A4 가로 문서용으로 표 최대 폭 넓히기 — 159·160·161·173·174·178줄의 150 을 모두 237(A4 가로 297mm − 좌우 여백 60mm) 등으로 바꿉니다. 한 곳만 바꾸면 축소 계산이 어긋납니다.
  • 테두리를 회색으로 — 181줄과 211줄의 #000000 을 #808080 으로 바꿉니다. HTML 색은 RRGGBB 순서이므로 Excel 의 RGB()/BGR 값과 순서가 다릅니다.

고칠 때 주의

  • 한글은 <colgroup> 을 무시하고 td 의 width 만 따르므로, 열 너비를 바꿀 때는 209줄 width 속성과 211줄 style width 를 함께 고쳐야 합니다.
  • CF_HTML 헤더의 위치 값은 UTF-8 바이트 수 기준입니다. 문자 수(Len)로 바꾸면 한글이 섞인 표가 깨집니다.
  • API 선언(9-29줄)은 64비트·32비트 두 갈래를 함께 고쳐야 합니다.

14학교명·지원청 교명 확인

약칭을 정식 교명으로, 오른쪽 셀에 지원청 표시. 바뀐 내용은 '변경내용' 시트에 정리.

모듈 4개 · 1,672줄 · 리본 버튼 → 진입 프로시저 학교명변환 (modSchoolName)

modSchoolName 표준 모듈 · 423줄

리본 tag "학교명변환" 진입점(6개 메뉴)과 범위 실행(SN_RunOnRange), 배열 기반 일괄 처리(SN_Process), 지원청 열 처리, 변경내용 시트 기록을 담당합니다.

소스 보기 (423줄)
modSchoolData 표준 모듈 · 842줄

학교 마스터 데이터 저장소입니다. 학교급별 내장 목록(Embed_초/중/고 프로시저 안의 L "정식명|지원청코드|설립구분" 줄)과 현황시트를 Scripting.Dictionary 에 적재하고, SD_Lookup·SD_Names 같은 조회 함수만 바깥에 공개합니다.

소스 보기 (842줄)
modSchoolMatch 표준 모듈 · 235줄

약칭 → 정식명 판정 엔진입니다. 정확 일치, 접미사 규칙 후보, 같은 학교급 안의 유사 검색 3단계로 결과 코드(SM_EXACT·SM_CONVERTED·SM_AMBIGUOUS·SM_NOTFOUND·SM_SKIP)를 돌려주고, 정식명 → 약칭 변환도 제공합니다.

소스 보기 (235줄)
modSchoolSheet 표준 모듈 · 172줄

학교급별 현황시트(연번·학교명·지원청·설립구분·약칭·비고)를 내장 데이터로 만들어 깔끔한 표 서식을 입히는 모듈입니다. 사용자가 이 시트를 고쳐 두면 이후 판정에 우선 적용됩니다.

소스 보기 (172줄)
심화과정: 소스 분석

선택한 열의 줄여 쓴 학교명(○○초·○○여중·○○공고 등)을 규칙과 학교 마스터 데이터로 판정해 정식 학교명으로 바꾸고, 오른쪽 열에 관할 지원청을 적습니다. 값은 배열로 한 번에 읽어 메모리에서 판정한 뒤 바뀐 셀만 기록하며, 후보가 여럿이면 연노랑, 목록에 없으면 연빨강으로 표시하고 모든 변경 내역을 '변경내용' 시트에 링크와 함께 남깁니다. 마스터 데이터는 문서에 '초등학교현황'·'중학교현황'·'고등학교현황' 시트가 있으면 그 시트를, 없으면 코드에 내장된 공립·사립 학교 목록을 씁니다.

모듈 구성

  • modSchoolName — 리본 tag "학교명변환" 진입점(6개 메뉴)과 범위 실행(SN_RunOnRange), 배열 기반 일괄 처리(SN_Process), 지원청 열 처리, 변경내용 시트 기록을 담당합니다.
  • modSchoolMatch — 약칭 → 정식명 판정 엔진입니다. 정확 일치, 접미사 규칙 후보, 같은 학교급 안의 유사 검색 3단계로 결과 코드(SM_EXACT·SM_CONVERTED·SM_AMBIGUOUS·SM_NOTFOUND·SM_SKIP)를 돌려주고, 정식명 → 약칭 변환도 제공합니다.
  • modSchoolData — 학교 마스터 데이터 저장소입니다. 학교급별 내장 목록(Embed_초/중/고 프로시저 안의 L "정식명|지원청코드|설립구분" 줄)과 현황시트를 Scripting.Dictionary 에 적재하고, SD_Lookup·SD_Names 같은 조회 함수만 바깥에 공개합니다.
  • modSchoolSheet — 학교급별 현황시트(연번·학교명·지원청·설립구분·약칭·비고)를 내장 데이터로 만들어 깔끔한 표 서식을 입히는 모듈입니다. 사용자가 이 시트를 고쳐 두면 이후 판정에 우선 적용됩니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modSchoolName 17~45줄(학교명변환, SN_MakeSheet)① 메뉴 선택(공통 허브가 자동 백업)리본 허브 UI_Run 은 이 기능을 삭제·치환 계열로 보고 실행 직전에 활성 시트를 숨김 백업 시트로 복사합니다. UI_Choose 로 '학교명 정리 + 지원청', '학교명 정리만', 초·중·고 현황시트 만들기, 세 시트 모두 만들기 중 하나를 고르면 SN_RunOnRange, SN_MakeSheet(→SS_Create), SS_CreateAll 로 갈라집니다.
  2. modSchoolName 48~93줄(SN_RunOnRange), 234-258 (SN_OfficeMode)② 범위 받기와 지원청 열 처리 방식Application.InputBox(Type:=8) 로 학교명 범위를 받고 첫 열만, 사용 영역과 겹치는 부분만 남깁니다. SD_Load True 로 현황시트 유무를 다시 확인해 데이터를 적재합니다. 지원청을 표시할 때는 오른쪽 열에 지원청이 아닌 값이 있는지 SD_IsOfficeText 로 세어, 있으면 '새 열 끼워 넣기 / 덮어쓰기 / 학교명만 / 취소' 를 묻고 필요하면 EntireColumn.Insert 로 열을 넣습니다.
  3. modSchoolMatch 64~120줄(SM_Resolve, SM_Candidates)③ 판정 1·2단계: 정확 일치와 접미사 규칙공백·전각 공백·줄바꿈을 지운 뒤 2자 미만, 숫자, 공백이 2개 이상인 문장, '비고·참고·광고' 같은 흔한 낱말은 SM_SKIP 으로 건너뜁니다. 마스터에 그대로 있으면 SM_EXACT 입니다. 아니면 SM_Rules 의 "약칭|정식" 쌍(예: 약칭 접미사 → 정식 접미사, 초→초등학교 …, 긴 것부터)으로 접미사를 바꾼 후보와, 지역명 접두어를 붙인 후보, '학교' 만 붙인 후보를 만들어 차례로 대조합니다.
  4. modSchoolMatch 123~216줄(SM_Fuzzy, SM_SplitStem, SM_StemMatch, SM_TypeMatch)④ 판정 3단계: 같은 학교급 유사 검색끝 글자로 학교급(초·중·고)을 추정하고, 약칭을 앞부분(stem)과 유형 키(여·공·상·과·외·예·체)로 나눕니다. 같은 급 목록에서 앞부분으로 시작하고 유형이 맞는 학교를 찾고, 없으면 포함 검색으로 넓힙니다. 1개면 SM_CONVERTED, 여러 개면 후보 목록을 비고에 담아 SM_AMBIGUOUS, 0개면 SM_NOTFOUND 를 돌려줍니다.
  5. modSchoolData 14~179줄(SD_Load, SD_LoadFromSheet, SD_LoadEmbedded, L)⑤ 마스터 데이터 적재정식명 → Array(급, 지원청, 설립구분) 사전(mAll)과 급별 사전(mLevel(1 To 3))을 Scripting.Dictionary 로 만듭니다. 급마다 현황시트에서 '학교명' 머리글을 A1:H8 에서 Find 로 찾고 '지원청'·'설립구분' 열을 읽으며, 시트가 없으면 내장 목록을 씁니다. 내장 목록(183줄 이후)은 학교급별 프로시저 안에 L "정식명|지원청코드|설립구분" 한 줄씩 들어 있고, 지원청 코드는 SD_OfficeName 이 '코드+지원청' 또는 '본청' 으로 바꿉니다.
  6. modSchoolName 96~231줄(SN_Process)⑥ 배열 판정 후 바뀐 셀만 기록범위 값을 Value2 배열로 한 번에 읽어 셀마다 SM_Resolve 결과를 배열에 담습니다(시트 접근 없음). 그다음 화면·계산·이벤트를 끄고, 수식 셀은 제외하며 이전 실행의 색 표시를 지웁니다. 오른쪽 열에 병합이 없으면 학교명 열 서식을 PasteSpecial xlPasteFormats 로 한 번에 복사하고, 변환된 셀만 값을 바꾸며 확인 필요·목록 없음 셀은 색을 칠합니다. 지원청 값은 대상 행의 연속 구간마다 배열로 한 번에 씁니다(SN_WriteOfficeRun, 텍스트 형식 @).
  7. modSchoolName 279~352줄(SN_LogChange, SN_WriteChangeSheet)⑦ 변경내용 시트변환·확인 필요·목록 없음 건을 2차원 배열에 모았다가 '변경내용' 시트에 No./셀/이전 학교명/변경된 학교명/구분/비고 로 한 번에 씁니다. 셀 주소 칸에는 Hyperlinks.Add 로 원본 셀로 가는 링크를 걸고, 구분 칸도 같은 표시색으로 칠합니다.
  8. modSchoolSheet 17~172줄(SS_Create, SS_CreateAll, SS_ApplyStyle)⑧ 현황시트 만들기같은 이름 시트가 있으면 '새로 만들기 / 그대로 두기 / 취소' 를 묻습니다. SD_EmbeddedRows 로 내장 목록을 2차원 배열로 받아 4행 머리글 아래에 연번·학교명·지원청·설립구분·약칭(SM_Abbrev)·비고(폐교·개교 예정·분교장 등)를 채웁니다. 서식은 회색 머리글, 머리카락 굵기 가로선, 고정 열 너비, 눈금선 숨김, 틀 고정, 자동 필터, 시트 탭 색으로 꾸밉니다.

핵심 VBA 객체·함수

  • CreateObject("Scripting.Dictionary") (.Exists, .Add, .Keys) — 학교 정식명을 키로 급·지원청·설립구분을 빠르게 찾는 사전 개체입니다.
  • Range.Value2 (배열 읽기·쓰기) — 범위 전체 값을 2차원 배열로 한 번에 읽고, 지원청 값도 배열로 한 번에 써서 셀 단위 접근을 줄입니다.
  • Range.HasFormula / Range.MergeCells / Range.Interior.Color (범위 전체) — 범위 전체에 물으면 모두 같을 때 True/False, 섞여 있으면 Null 을 돌려줍니다. 이를 이용해 셀마다 검사할지 결정합니다.
  • Range.PasteSpecial xlPasteFormats — 학교명 열의 서식만 지원청 열에 복사합니다.
  • Worksheet.Hyperlinks.Add Anchor, Address:="", SubAddress:="'시트'!A1" — 같은 통합 문서 안 셀로 이동하는 내부 링크를 만듭니다.
  • Range.Find("학교명", LookIn:=xlValues, LookAt:=xlWhole) — 현황시트 위쪽에서 머리글 위치를 찾아 사용자가 열 순서를 바꿔도 읽을 수 있게 합니다.
  • Range.EntireColumn.Insert Shift:=xlToRight — 오른쪽 열에 다른 값이 있을 때 지원청용 새 열을 끼워 넣습니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 메뉴, 오른쪽 열 처리 방식, 기존 현황시트 처리 선택
  • UI_Run / UI_MakeBackup (modRibbonUI) — 실행 직전 활성 시트를 숨김 백업 시트로 복사
  • UI_RestoreBackup (modRibbonUI) — 결과 메시지가 안내하는 되돌리기

이렇게 고쳐 쓰세요

  • '확인 필요' 표시색을 연한 주황으로 — modSchoolName 13줄 CLR_MARK_AMB As Long = &HB3F0FF 를 바꿉니다. 16진 상수는 BGR(&H00BBGGRR) 순서라 RGB(255,240,179) 가 &HB3F0FF 로 적혀 있습니다. 연한 주황 RGB(255,214,153) 은 &H99D6FF 로 씁니다.
  • 새 약칭 규칙 추가 — modSchoolMatch 31줄 배열 끝 "고|고등학교") 앞에 "새약칭|정식 접미사", _ 처럼 넣습니다. 규칙은 위에서부터 검사하므로 짧은 '고' 규칙보다 앞에 둬야 합니다.
  • 학교로 오인되는 낱말 제외 추가 — modSchoolMatch 37-39줄 SM_IsCommonWord 의 Array 목록에 "최중" 같은 낱말을 쉼표로 이어 추가합니다.
  • 내장 데이터 갱신 — 코드를 고치지 않아도 현황시트(B열 학교명·C열 지원청·D열 설립구분)를 고쳐 두면 우선 적용됩니다. 내장 목록을 바꾸려면 modSchoolData 의 학교급별 프로시저 안 L "정식명|지원청코드|설립구분" 줄을 추가·수정합니다.

고칠 때 주의

  • SM_Rules 순서가 바뀌면 '여상' 보다 '상' 류 규칙이 먼저 걸리는 등 판정이 달라집니다. 긴 접미사가 먼저 오도록 유지합니다.
  • 같은 이름의 현황시트를 '새로 만들기' 하면 직접 고친 내용이 사라집니다.
  • 변경내용 시트는 실행할 때마다 새로 쓰므로, 이전 실행의 기록은 남지 않습니다.

15메모배경넣기 기타기능

복사한 캡처 이미지를 셀 메모 배경으로.

모듈 1개 · 275줄 · 리본 버튼 → 진입 프로시저 메모에이미지넣기 (modMemoImage)

modMemoImage 표준 모듈 · 275줄

리본 tag "메모에이미지넣기" 진입점과 실제 작업(MemoImage_Run), 키 입력·클립보드 확인 API 선언, PowerShell 로 클립보드 그림 크기 조회·PNG 저장 함수를 담은 단일 모듈입니다.

소스 보기 (275줄)
심화과정: 소스 분석

클립보드에 이미 그림이 있으면 그것을 쓸지 묻고, 없거나 새로 찍기로 하면 keybd_event API 로 Win+Shift+S 키를 눌러 Windows 화면 캡처를 띄웁니다. 숨김 PowerShell 을 실행해 .NET 클립보드 API 로 그림 크기를 읽고 임시 폴더에 PNG 로 저장한 뒤, 사용자가 고른 셀에 메모를 만들어 그 PNG 를 메모 도형의 배경 그림(Fill.UserPicture)으로 채웁니다. 메모 크기는 픽셀을 96dpi 기준 포인트로 바꿔 맞추고 최소·최대 크기를 제한합니다.

모듈 구성

  • modMemoImage — 리본 tag "메모에이미지넣기" 진입점과 실제 작업(MemoImage_Run), 키 입력·클립보드 확인 API 선언, PowerShell 로 클립보드 그림 크기 조회·PNG 저장 함수를 담은 단일 모듈입니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modMemoImage 107~114줄(메모에이미지넣기)① 리본 콜백과 지연 실행리본 콜백 안에서 바로 Application.InputBox(Type:=8) 를 띄우면 셀 선택 창이 곧바로 취소되는 문제가 있어, control 이 있으면 Application.OnTime Now 로 MemoImage_Run 을 콜백이 끝난 직후에 실행하도록 예약합니다. 공통 허브 UI_Run 처럼 Nothing 으로 부르면 바로 실행합니다.
  2. modMemoImage 116~150줄(MemoImage_Run)② 클립보드 그림 확인과 화면 캡처IsClipboardFormatAvailable(CF_BITMAP) 으로 클립보드에 그림이 있는지 보고, 있으면 UI_Choose 로 '클립보드 이미지 사용' 과 '새로 캡처' 중 고르게 합니다. 캡처가 필요하면 keybd_event 로 Win·Shift·S 키를 차례로 누르고(50ms 뒤) 떼어 Windows 캡처 도구를 띄우고, 메시지 상자로 사용자가 캡처를 마칠 때까지 기다립니다. 그래도 그림이 없으면 안내 후 끝냅니다.
  3. modMemoImage 36~102줄(SaveClipboardToPNG, GetClipboardImageSize)③ PowerShell 로 크기 조회와 PNG 저장WScript.Shell.Run 으로 창을 숨긴 PowerShell 을 동기 실행(0, True)합니다. [System.Windows.Forms.Clipboard]::GetImage() 로 그림을 얻어 크기는 TEMP 폴더 텍스트 파일에 '가로,세로' 로 적은 뒤 VBA 가 Open ... For Input 으로 읽고 지우며, 그림은 $img.Save(경로, ImageFormat::Png) 로 원본 그대로 저장합니다. 저장 여부는 Dir(경로) 로 확인합니다.
  4. modMemoImage 161~201줄(MemoImage_Run)④ 대상 셀 고르기TEMP 폴더에 날짜·시각이 붙은 PNG 를 저장한 뒤, 외부 프로세스 실행으로 넘어간 포커스를 AppActivate Application.Caption 으로 Excel 에 되돌립니다. Application.InputBox(Type:=8) 로 메모를 넣을 셀을 고르게 하고, 취소하면 임시 PNG 를 지우고 끝냅니다. 여러 셀을 골라도 첫 셀만 씁니다.
  5. modMemoImage 203~251줄(MemoImage_Run)⑤ 메모 만들고 그림 배경 채우기기존 메모가 있으면 지우고 AddComment 로 공백 한 칸짜리 메모를 만듭니다. 픽셀을 × 72 / 96 으로 포인트로 바꿔 메모 도형 크기를 정하고, 너비 150 미만·높이 100 미만이면 비율을 유지해 키우고, 너비 600 초과면 줄입니다. .Fill.UserPicture tempPath 로 PNG 를 배경으로 넣고, 메모 글자는 흰색 1pt 로 숨긴 뒤 메모를 평소에는 숨김(마우스를 올리면 표시) 상태로 둡니다.
  6. modMemoImage 253~275줄(MemoImage_Run)⑥ 임시 파일 삭제와 완료 안내그림은 이미 메모에 포함되었으므로 Kill 로 임시 PNG 를 지웁니다. 셀을 선택하고 셀 주소와 이미지 픽셀 크기를 메시지로 보여 줍니다.

핵심 VBA 객체·함수

  • keybd_event (user32) — 키보드 키를 누르고 떼는 동작을 흉내 내는 Windows API 입니다. Win+Shift+S 조합으로 화면 캡처 도구를 엽니다.
  • IsClipboardFormatAvailable(CF_BITMAP) (user32) — 클립보드에 비트맵 그림(형식 번호 2)이 있는지 확인합니다.
  • CreateObject("WScript.Shell").Run psCmd, 0, True — 명령을 창 숨김(0)으로 실행하고 끝날 때까지 기다립니다(True).
  • [System.Windows.Forms.Clipboard]::GetImage() / $img.Save(..., ImageFormat::Png) — PowerShell 안에서 .NET 으로 클립보드 그림을 얻어 PNG 파일로 저장합니다.
  • Range.AddComment / Comment.Shape.Fill.UserPicture — 셀에 메모(노트)를 만들고, 메모 도형의 채우기를 그림 파일로 지정합니다.
  • Application.OnTime Now, "'파일명'!MemoImage_Run" — 지정한 매크로를 현재 작업(리본 콜백)이 끝난 뒤 실행하도록 예약합니다.
  • Application.InputBox(Type:=8) — 시트에서 마우스로 셀을 선택해 Range 로 받습니다.

부르는 공통 함수

  • UI_Choose (modRibbonUI) — 클립보드 그림 사용/새 캡처 선택 폼
  • UI_Run (modRibbonUI) — 리본 tag "메모에이미지넣기" 를 받아 Nothing 인수로 호출

이렇게 고쳐 쓰세요

  • 메모 최대 너비를 600pt 에서 800pt 로 — 235·237·238줄의 600 세 곳을 모두 800 으로 바꿉니다.
  • 메모를 항상 보이게 하기 — 251줄 rng.Comment.Visible = False 를 True 로 바꿉니다.
  • 고해상도(125% 배율) 화면에서 크기 맞추기 — 214·215줄의 96# 을 120# 으로 바꾸면 같은 픽셀이 더 작은 포인트로 환산됩니다.

고칠 때 주의

  • PowerShell 실행이 정책으로 막힌 PC 에서는 크기 조회 단계에서 실패합니다.
  • 저장 경로는 PowerShell 명령 문자열 안에 작은따옴표로 들어가므로(46·75줄), TEMP 경로에 작은따옴표가 있으면 명령이 깨집니다.
  • Win+Shift+S 캡처 도구는 Windows 10 이상에서만 동작합니다.

16백업 시트 복원 안전장치

삭제·치환 기능 실행 직전 자동 백업(최근 3개)을 표시하거나 원본에 덮어써 복원.

모듈 1개 · 401줄 · 리본 버튼 → 진입 프로시저 UI_RestoreBackup (modRibbonUI)

modRibbonUI 표준 모듈 · 401줄

리본·도형 버튼 공통 진입점(UI_Ribbon, UI_ShapeClick, UI_Run)과 자동 백업·복원, 그리고 선택/입력 폼 래퍼(UI_Choose, UI_ChooseEx, UI_Input)를 모은 허브 모듈입니다.

소스 보기 (401줄)
심화과정: 소스 분석

리본의 모든 버튼은 UI_Ribbon 이 받은 tag 문자열을 UI_Run 에 넘기는 하나의 허브로 들어오며, UI_Run 은 Excel 설정을 보관·복원하고 삭제 계열 기능(빈칸삭제·중복셀값제거·학교명변환) 직전에 활성 시트를 '백업_원본이름_시분초' 숨김 시트로 복사합니다(최근 3개만 보관). '백업 시트 복원' 은 가장 최근 백업 시트를 찾아 이름에서 원본 시트를 추정한 뒤, 백업을 보여 주기만 하거나 원본 시트 내용을 백업 내용으로 덮어씁니다.

모듈 구성

  • modRibbonUI — 리본·도형 버튼 공통 진입점(UI_Ribbon, UI_ShapeClick, UI_Run)과 자동 백업·복원, 그리고 선택/입력 폼 래퍼(UI_Choose, UI_ChooseEx, UI_Input)를 모은 허브 모듈입니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modRibbonUI 23~35줄(UI_Ribbon, UI_ShapeClick)① 리본·도형 버튼의 공통 입구리본 XML 의 모든 버튼은 onAction 으로 UI_Ribbon 을 부르고, 버튼의 tag 값(예: "UI_RestoreBackup")을 UI_Run 에 넘깁니다. 시트 위 도형 버튼은 UI_ShapeClick 이 Application.Caller 로 눌린 도형을 찾아 그 도형의 대체 텍스트(AlternativeText)를 프로시저 이름으로 넘깁니다.
  2. modRibbonUI 37~58줄(UI_Run)② 실행 환경 보관과 사전 처리실행 중 중복 클릭은 busy 플래그로 막습니다. 활성 통합 문서가 없거나 추가 기능 자체면 새 문서를 만들고, 계산 방식·이벤트·화면 갱신·알림·상태 표시줄·AutomationSecurity 를 변수에 보관합니다. UI_IsDestructive 가 참이면 UI_MakeBackup 으로 백업하고, UI_NeedsNewFile 이 참인 기능은 새 통합 문서를 열어 그 안에서 실행합니다.
  3. modRibbonUI 59~130줄(UI_Run)③ tag → 기능 프로시저 분기와 복원Select Case proc 로 tag 문자열마다 해당 기능을 호출합니다(리본 콜백 형식의 기능에는 Nothing 을 넘김). 등록되지 않은 tag 는 Err.Raise 로 오류를 냅니다. 성공·실패와 관계없이 CleanExit 에서 보관해 둔 Excel 설정을 모두 되돌리고, 오류가 있었으면 작업 이름·오류 번호·진단 단계(BX_Trace)를 메시지로 보여 줍니다.
  4. modRibbonUI 161~207줄(UI_IsDestructive, UI_MakeBackup, UI_TrimBackups)④ 자동 백업 만들기와 3개 유지삭제 계열 tag 이면 ws.Copy After:= 로 시트를 맨 뒤에 복사하고, 이름을 백업_ + 원본 이름 앞 18자 + _hhmmss 로 바꾼 뒤 xlSheetHidden 으로 숨깁니다. 이미 백업 시트이면 다시 백업하지 않습니다. UI_TrimBackups 는 '백업_' 시트 수를 세어 3개(BACKUP_KEEP)를 넘으면 앞쪽(오래된) 것부터 삭제합니다.
  5. modRibbonUI 209~231줄(UI_RestoreBackup)⑤ 최근 백업과 원본 시트 찾기시트를 차례로 보며 '백업_' 으로 시작하는 시트 수를 세고 마지막으로 만난 것을 가장 최근 백업으로 봅니다. 없으면 자동 백업이 만들어지는 기능을 안내하고 끝냅니다. 백업 이름에서 접두어와 마지막 _시분초 를 떼어 내 원본 이름 앞 18자(stem)를 얻고, 이름 앞 18자가 같은 일반 시트를 원본으로 찾습니다.
  6. modRibbonUI 232~254줄(UI_RestoreBackup)⑥ 표시 또는 덮어쓰기 복원UI_Choose 로 '백업 시트만 표시', '원본에 덮어쓰기', '취소' 를 고르게 합니다. 1번은 백업 시트를 xlSheetVisible 로 보이게 하고 활성화합니다. 2번은 원본을 찾은 경우에만 orig.Cells.Clear 로 비운 뒤 latest.Cells.Copy orig.Cells(1, 1) 로 값·서식을 통째로 복사합니다.
  7. modRibbonUI 258~276줄, 343-381 (UI_Choose, UI_ChoiceToMsg, UI_Input, UI_ChooseEx)⑦ 공통 폼 래퍼다른 기능들이 쓰는 선택·입력 폼 호출도 이 모듈에 있습니다. UI_Choose 는 frmChoice 를 만들어 Setup·Show vbModal 후 Result(취소=0)를 돌려주고, 검증용 BX_Silent 가 켜져 있으면 폼 없이 0을 반환합니다. UI_ChoiceToMsg 는 1/2/그 외를 vbYes/vbNo/vbCancel 로 바꾸고, UI_Input 은 frmInput 으로 문자열을, UI_ChooseEx 는 미리보기·체크 항목 값까지 받아 옵니다.

핵심 VBA 객체·함수

  • IRibbonControl.Tag — 리본 XML 에서 버튼마다 지정한 tag 문자열입니다. 하나의 콜백(UI_Ribbon)으로 모든 버튼을 구분하는 데 씁니다.
  • Application.Caller — 도형 버튼에서 매크로를 실행했을 때 눌린 도형의 이름을 돌려줍니다.
  • Worksheet.Copy After:=wb.Worksheets(wb.Worksheets.Count) — 시트를 같은 통합 문서 맨 뒤에 복사합니다. 복사본이 새 마지막 시트가 됩니다.
  • Worksheet.Visible = xlSheetHidden / xlSheetVisible — 백업 시트를 숨기거나 다시 보이게 합니다(시트 숨기기 취소 메뉴로도 볼 수 있는 일반 숨김).
  • Range.Copy Destination — latest.Cells.Copy orig.Cells(1, 1) 처럼 시트 전체 셀을 값·서식째 다른 시트에 복사합니다.
  • Application.AutomationSecurity = msoAutomationSecurityForceDisable — 기능 실행 중 코드로 여는 파일의 매크로가 자동 실행되지 않게 하고, 끝나면 원래 값으로 되돌립니다.
  • Err.Raise vbObjectError + 221 — 등록되지 않은 tag 에 대해 사용자 정의 오류를 일으켜 공통 오류 메시지로 보냅니다.

부르는 공통 함수

  • frmChoice (폼) — UI_Choose·UI_ChooseEx 가 띄우는 카드형 선택 폼
  • frmInput (폼) — UI_Input 이 띄우는 입력 폼
  • BX_EnsureBoardEvents (다른 모듈) — UI_Run 시작 시 호출되는 이벤트 준비 루틴

이렇게 고쳐 쓰세요

  • 백업 시트를 3개가 아니라 5개까지 보관 — 14줄 Private Const BACKUP_KEEP As Long = 3 의 3 을 5 로 바꿉니다. 복원 폼 안내 문구도 이 상수를 쓰므로 함께 바뀝니다.
  • 다른 기능(예: 테두리 스타일)도 실행 전 자동 백업 — 163줄 Case "b빈칸삭제", "c중복셀값제거", "학교명변환" 끝에 , "테두리선스타일" 처럼 리본 tag 이름을 추가합니다. 220줄 안내 문구도 맞춰 고칩니다.
  • 백업 시트를 완전히 숨기기(시트 숨기기 취소 메뉴에 안 보이게) — 179줄 copyWs.Visible = xlSheetHidden 을 xlSheetVeryHidden 으로 바꿉니다. 복원 기능의 '표시' 는 237줄에서 xlSheetVisible 로 바꾸므로 그대로 동작합니다.

고칠 때 주의

  • 원본 찾기는 시트 이름 앞 18자 비교라, 앞 18자가 같은 시트가 여러 개면 첫 번째 시트가 원본으로 잡힐 수 있습니다.
  • '가장 최근' 백업은 시트 순서상 마지막 백업 시트입니다. 백업 시트를 직접 옮기면 판단이 달라집니다.
  • 덮어쓰기 복원은 원본 시트의 셀을 모두 지운 뒤 복사하므로 백업 이후에 한 작업은 사라집니다.

17사용방법 B-xlam

설치·기능별 사용설명 페이지(https://140-245-77-55.sslip.io/xlam) 열기.

모듈 1개 · 12줄 · 리본 버튼 → 진입 프로시저 OpenHelpWebsite (modHelpSite)

modHelpSite 표준 모듈 · 12줄

리본 tag "OpenHelpWebsite" 진입점 하나로 사용설명서 웹 페이지를 브라우저로 엽니다.

소스 보기 (12줄)
심화과정: 소스 분석

리본 버튼이 OpenHelpWebsite 를 부르면 사용설명서 주소를 문자열 변수에 담아 ThisWorkbook.FollowHyperlink 로 기본 브라우저에서 엽니다. 열기에 실패하면 오류 처리기로 건너뛰어 주소와 오류 내용을 메시지 상자로 보여 줍니다.

모듈 구성

  • modHelpSite — 리본 tag "OpenHelpWebsite" 진입점 하나로 사용설명서 웹 페이지를 브라우저로 엽니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modHelpSite 3~4줄(OpenHelpWebsite)① 리본 콜백 선언control As IRibbonControl 인수를 받는 리본 콜백 형식입니다. 실제로는 공통 허브 UI_Run 이 OpenHelpWebsite Nothing 으로 부르므로 인수는 쓰지 않습니다. 4줄에서 주소를 담을 문자열 변수 url 을 선언합니다.
  2. modHelpSite 5줄② 사용설명서 주소 지정url = "https://140-245-77-55.sslip.io/xlam" 로 열 주소를 정합니다. 주소를 바꾸려면 이 한 줄만 고치면 됩니다.
  3. modHelpSite 6~8줄③ 오류 처리기 설정과 브라우저 열기On Error GoTo Fail 로 이후 오류가 나면 Fail 레이블로 가게 합니다. ThisWorkbook.FollowHyperlink Address:=url 은 하이퍼링크를 클릭한 것처럼 기본 브라우저로 주소를 엽니다. 성공하면 Exit Sub 로 오류 처리기를 건너뛰고 끝납니다.
  4. modHelpSite 9~12줄(Fail)④ 실패 시 안내보안 정책 등으로 열지 못하면 Fail 레이블로 와서 주소와 Err.Description(오류 설명)을 포함한 경고 메시지를 띄워, 사용자가 브라우저에 주소를 직접 입력할 수 있게 합니다.

핵심 VBA 객체·함수

  • ThisWorkbook.FollowHyperlink Address:=url — 주소를 하이퍼링크처럼 열어 기본 브라우저에서 웹 페이지를 띄웁니다.
  • On Error GoTo Fail — 오류가 나면 지정한 레이블로 실행 위치를 옮기는 VBA 오류 처리 구문입니다.
  • Err.Description — 마지막으로 발생한 오류의 설명 문자열입니다.

부르는 공통 함수

  • UI_Ribbon / UI_Run (modRibbonUI) — 리본 tag "OpenHelpWebsite" 를 받아 이 프로시저를 Nothing 인수로 호출

이렇게 고쳐 쓰세요

  • 다른 도움말 주소 열기 — 5줄 url = "https://140-245-77-55.sslip.io/xlam" 의 따옴표 안 주소를 원하는 주소로 바꿉니다. 10줄 메시지에도 같은 변수가 쓰이므로 따로 고칠 필요가 없습니다.
  • 메시지 상자 제목 바꾸기 — 11줄 끝의 제목 문자열(vbExclamation, 뒤 따옴표 안)을 원하는 이름으로 바꿉니다.

고칠 때 주의

  • 회사·기관 PC 의 보안 정책이 하이퍼링크 열기를 막으면 항상 실패 메시지가 뜹니다. 이 경우 코드가 아니라 정책 문제입니다.

공통공통 모듈·폼 공통

여러 기능이 함께 쓰는 선택 폼(애플 스타일 카드)·미리보기 그림·입력 폼 코드입니다.

모듈 5개 · 736줄

modUITheme 표준 모듈 · 377줄

폼 공통 디자인 모듈입니다. 색(BGR 16진 상수)·글꼴·치수 상수와 제목·안내문·옵션 카드·버튼·입력 상자·구분선 스타일 함수, 호버 색 전환, 카드 오른쪽 미리보기(UI_DrawPreview) 그리기를 제공합니다.

소스 보기 (377줄)
clsUIButton 클래스 모듈 · 31줄

동적으로 만든 MSForms.Label 을 WithEvents 로 붙잡아 클릭·마우스 이동 이벤트를 소유 폼의 OnPick / OnExtra / OnHover 로 전달하는 이벤트 래퍼 클래스입니다.

소스 보기 (31줄)
frmChoice 사용자 정의 폼(코드) · 193줄

UI_Choose·UI_ChooseEx 가 띄우는 선택 폼의 코드 비하인드입니다. 최대 6개 카드, 미리보기, 단일 선택 체크 항목, 숫자키·Esc 키 처리를 담당하며 Result(취소=0)와 Extra 를 공개합니다. 폼 크기·기본 컨트롤 배치 등 시각적 레이아웃 원본은 함께 저장되는 .frx 바이너리 파일에 있고, 이 코드는 그 기본 컨트롤(btn1~6, btnCancel, lblPrompt)을 숨긴 뒤 새로 그립니다.

폼은 화면 배치(.frx)가 xlam 안에 있어 코드만 복사 제공
소스 보기 (193줄)
frmInput 사용자 정의 폼(코드) · 119줄

UI_Input 이 띄우는 입력 폼의 코드 비하인드입니다. .frx 에 있는 txtValue 입력 상자는 그대로 쓰고 btnOK·btnCancel·lblPrompt 는 숨긴 채 라벨 버튼을 새로 만들며, Enter/Esc, 숫자만 입력 검사, Cancelled 속성을 제공합니다.

폼은 화면 배치(.frx)가 xlam 안에 있어 코드만 복사 제공
소스 보기 (119줄)
modTestHooks 표준 모듈 · 16줄

리본에 연결되지 않은 빌드 검증용 훅입니다. 외부 검증 스크립트가 Application.Run 으로 폼 생략 모드·테스트 폴더를 설정하고 표 복사 기능을 시험합니다.

소스 보기 (16줄)
심화과정: 소스 분석

여러 기능이 함께 쓰는 선택 폼(frmChoice)과 입력 폼(frmInput)은 폼 디자이너에 놓인 기본 버튼을 숨기고, 실행 시점에 Controls.Add("Forms.Label.1") 로 라벨을 만들어 카드형 항목·버튼·미리보기를 그립니다. 라벨에는 클릭 이벤트가 없으므로 WithEvents 래퍼 클래스 clsUIButton 이 클릭·마우스 이동을 받아 폼의 OnPick·OnHover 를 대신 호출하고, 색·글꼴·치수는 modUITheme 상수 한 곳에서 관리합니다. modTestHooks 는 자동 검증용 진입점이며, Sheet1 과 현재_통합_문서(ThisWorkbook) 문서 모듈은 코드가 비어 있습니다.

모듈 구성

  • modUITheme — 폼 공통 디자인 모듈입니다. 색(BGR 16진 상수)·글꼴·치수 상수와 제목·안내문·옵션 카드·버튼·입력 상자·구분선 스타일 함수, 호버 색 전환, 카드 오른쪽 미리보기(UI_DrawPreview) 그리기를 제공합니다.
  • clsUIButton — 동적으로 만든 MSForms.Label 을 WithEvents 로 붙잡아 클릭·마우스 이동 이벤트를 소유 폼의 OnPick / OnExtra / OnHover 로 전달하는 이벤트 래퍼 클래스입니다.
  • frmChoice — UI_Choose·UI_ChooseEx 가 띄우는 선택 폼의 코드 비하인드입니다. 최대 6개 카드, 미리보기, 단일 선택 체크 항목, 숫자키·Esc 키 처리를 담당하며 Result(취소=0)와 Extra 를 공개합니다. 폼 크기·기본 컨트롤 배치 등 시각적 레이아웃 원본은 함께 저장되는 .frx 바이너리 파일에 있고, 이 코드는 그 기본 컨트롤(btn1~6, btnCancel, lblPrompt)을 숨긴 뒤 새로 그립니다.
  • frmInput — UI_Input 이 띄우는 입력 폼의 코드 비하인드입니다. .frx 에 있는 txtValue 입력 상자는 그대로 쓰고 btnOK·btnCancel·lblPrompt 는 숨긴 채 라벨 버튼을 새로 만들며, Enter/Esc, 숫자만 입력 검사, Cancelled 속성을 제공합니다.
  • modTestHooks — 리본에 연결되지 않은 빌드 검증용 훅입니다. 외부 검증 스크립트가 Application.Run 으로 폼 생략 모드·테스트 폴더를 설정하고 표 복사 기능을 시험합니다.
  • Sheet1 — 추가 기능 통합 문서의 워크시트 문서 모듈로, 코드가 없습니다(빈 모듈).
  • 현재_통합_문서 — 추가 기능 통합 문서(ThisWorkbook) 문서 모듈로, 코드가 없습니다. 통합 문서 열기 같은 이벤트 처리기는 정의되어 있지 않습니다.

코드 흐름 (줄 번호를 누르면 소스의 그 부분으로 이동)

  1. modRibbonUI 258-267 (UI_Choose) → frmChoice 15-24 (UserForm_Initialize, Setup) ① 폼 생성과 초기화기능 코드가 UI_Choose 를 부르면 New frmChoice 로 폼 인스턴스가 만들어지며 UserForm_Initialize 가 Result·Extra 를 0으로, 이벤트 래퍼 보관용 Collection 을 새로 만듭니다. Setup 은 미리보기·체크 항목 없이 SetupEx 를 부르는 단축형입니다.
  2. frmChoice 26~69줄(SetupEx), modUITheme 37-134② 디자이너 컨트롤 숨기고 카드 그리기UI_StyleForm 으로 흰 배경·폭 440·가운데 표시를 적용하고, .frx 에 배치된 btn1~btn6, btnCancel, lblPrompt 를 숨깁니다. 제목·안내문 라벨을 Controls.Add 로 만들어 UI_StyleTitle·UI_StylePrompt 로 꾸미고(AutoSize 를 켰다 끄는 방식으로 높이를 글자에 맞춤), 항목마다 카드 라벨(UI_StyleOption), 투명 글자 라벨(UI_StyleOptionText), 번호 라벨(UI_StyleOptionNum) 세 개를 겹쳐 놓고 y 좌표를 누적합니다.
  3. frmChoice 71~104줄, 107-139 (SetupEx, DrawPreviews, RefreshExtras), modUITheme 245-337 (UI_HexColor, UI_Box, UI_DrawPreview)③ 체크 항목·미리보기·취소 버튼체크 항목 배열이 있으면 한 줄에 균등 폭으로 □/■ 라벨을 만들고 기본 선택을 표시합니다. 그 아래 구분선과 '취소 (Esc)' 버튼을 그린 뒤 폼 높이를 내용에 맞춥니다. DrawPreviews 는 사양 문자열(stripe:RRGGBB, line:dot, merge:after 등)을 UI_DrawPreview 에 넘겨 작은 라벨 상자들로 줄무늬 표·선 모양·병합 전후 그림을 그리고, 체크 항목이 바뀌면 기존 미리보기 컨트롤을 지우고 선 굵기를 반영해 다시 그립니다.
  4. frmChoice 142~147줄(AddBtn), clsUIButton 1-31④ 라벨을 버튼으로: 이벤트 래퍼AddBtn 은 라벨마다 clsUIButton 인스턴스를 만들어 lbl(WithEvents), Owner(폼), Index, kind(0 카드, 1 주요 버튼, 2 보조 버튼, 3 글자 라벨, 4 체크 항목)를 넣고 Collection 에 보관합니다. 보관하지 않으면 개체가 사라져 이벤트도 끊깁니다. 클래스의 lbl_Click 은 kind 4 면 Owner.OnExtra, 그 밖은 Owner.OnPick 을, lbl_MouseMove 는 Owner.OnHover 를 부릅니다.
  5. frmChoice 150~193줄(OnPick, OnExtra, OnHover, UserForm_KeyDown, UserForm_QueryClose)⑤ 선택·호버·키보드·닫기 처리OnPick 은 Result 에 번호를 넣고 Me.Hide 로 모달을 풀어 호출 측으로 돌아갑니다(취소 버튼은 번호 0). OnHover 는 모든 래퍼의 SetHover 를 불러 같은 번호만 강조색(UI_Hover)으로 바꿉니다. 숫자 1~6(숫자 패드 포함)은 해당 항목 선택, Esc 는 취소이며, 창 닫기(X, CloseMode = 0)는 폼을 파괴하지 않고 숨겨 Result 0 을 읽을 수 있게 합니다. 호출 측 UI_Choose 가 Result 를 읽은 뒤 Unload 합니다.
  6. modRibbonUI 343-354 (UI_Input) → frmInput 8-119 ⑥ 입력 폼Setup 은 선택 폼과 같은 방식으로 제목·안내문을 그리고, .frx 의 txtValue 를 UI_StyleTextBox 로 꾸며 기본값을 넣은 뒤 '확인 (Enter)'·'취소 (Esc)' 라벨 버튼을 만듭니다. 표시될 때 입력 글자 전체를 선택하고, 확인 시 numericOnly 면 IsNumeric 으로 검사합니다. 결과는 Cancelled 속성과 txtValue.Text 로 호출 측에 전달됩니다.
  7. modTestHooks 1~16줄⑦ 검증용 훅BX_SetSilent 는 공용 변수 BX_Silent 를 켜서 UI_Choose 가 폼 없이 0을 반환하게 하고, BX_SetTestFolder 는 한글 합치기·PDF 변환 모듈의 폴더 대화상자를 생략할 경로를 지정합니다. BX_TestCopyTable 은 HC_CopyRangeAsTable 을 불러 '행x열' 또는 "FAIL" 을 돌려줍니다.

핵심 VBA 객체·함수

  • Me.Controls.Add("Forms.Label.1", name, True) — 실행 중에 사용자 폼에 Label 컨트롤을 새로 만들어 넣습니다. 카드·버튼·미리보기 상자가 모두 이 방식으로 만들어집니다.
  • Public WithEvents lbl As MSForms.Label — 클래스 모듈에서 컨트롤 이벤트(Click, MouseMove)를 받을 수 있게 선언합니다. 동적 컨트롤의 이벤트 처리에 필수입니다.
  • UserForm.Show vbModal / Me.Hide / Unload — 모달로 띄워 사용자가 고를 때까지 호출 코드를 멈추고, Hide 로 돌아간 뒤 결과를 읽고 Unload 로 해제합니다.
  • UserForm_QueryClose(Cancel, CloseMode) — 창 닫기(X) 시 Cancel = 1 로 폼 파괴를 막고 숨기기만 해 취소 결과를 안전하게 전달합니다.
  • UserForm_KeyDown(KeyCode) — vbKey1~vbKey6, vbKeyNumpad1~6, vbKeyEscape 를 받아 키보드로 선택·취소합니다.
  • RGB(CLng("&H" & Mid$(hex6, 1, 2)), ...) — UI_HexColor 가 "RRGGBB" 문자열을 Excel/VBA 색 값(BGR 순서 Long)으로 바꿉니다.

부르는 공통 함수

  • UI_Choose / UI_ChooseEx / UI_Input (modRibbonUI) — 이 폼들을 만들고 띄우는 공개 래퍼
  • BX_Silent (modRibbonUI) — 검증 모드에서 폼 표시를 생략하는 공용 변수
  • HC_CopyRangeAsTable (modHwpCopy) — modTestHooks 가 시험하는 표 복사 함수

이렇게 고쳐 쓰세요

  • 강조색(애플 블루)을 초록으로 — modUITheme 19줄 UI_ClrAccent As Long = &HFF7A00 을 바꿉니다. VBA 16진 색은 &H00BBGGRR(BGR) 순서라 RGB(0,122,255) 가 &HFF7A00 입니다. 초록 RGB(52,168,83) 은 &H53A834 로 쓰고, 눌림색 20줄 UI_ClrAccentDn 도 조금 어둡게 맞춥니다.
  • 폼을 더 넓게 — modUITheme 30줄 UI_FormWidth As Single = 440 을 520 등으로 바꿉니다. 카드·입력 상자 폭이 모두 이 상수에서 계산됩니다.
  • 폼 글꼴 바꾸기 — modUITheme 24줄 UI_FontName As String = "맑은 고딕" 의 글꼴 이름을 바꿉니다.
  • 선택 항목을 7개 이상 허용 — frmChoice 51줄 If n > 6 Then n = 6 의 6을 늘리면 되지만, 31-33줄의 btn1~btn6 숨김 반복과 180-183줄 숫자키 처리는 6까지만 다루므로 함께 검토해야 합니다.

고칠 때 주의

  • modUITheme 17줄 UI_ClrText = &H1C1C1E 는 주석의 (28,28,30) 과 BGR 순서가 반대로 적혀 실제로는 RGB(30,28,28) 입니다. 색을 고칠 때는 주석보다 16진 값의 BGR 순서를 기준으로 계산합니다.
  • 폼의 기본 컨트롤(btn1~6, btnCancel, btnOK, lblPrompt, txtValue)은 .frx 에 들어 있어 코드만으로는 보이지 않습니다. 이 이름을 폼 디자이너에서 바꾸거나 지우면 Setup 이 오류를 냅니다.
  • AddBtn 으로 만든 clsUIButton 을 Collection 에 보관하지 않으면 이벤트가 동작하지 않습니다.

소스·분석: 엑셀과 한글 매크로