• 최초 작성일: 2022-12-03
  • 최종 수정일: 2022-12-03
  • 조회수: 3,729 회
  • 작성자: 권현욱 (엑셀러)
  • 강의 제목: 최장 연승 기록 집계하기

들어가기 전에 ㅡ 그 지긋지긋하던 '경우의 수' 징크스를 깨다

우리나라의 월드컵 16강 도전 역사를 보면 흔히 이런 패턴으로 진행되곤 했다.

  • 조별 예선 1차전은 대체로 해볼만 한 상대와 붙는데 꼭 비기거나 진다(우루과이 전).
  • 2차전은 무조건 이겨야 하는데 1차전보다 못한 경기력을 펼친 끝에 또 비기거나 진다(가나 전).
  • 이제 3차전 밖에 기회가 없는데 하필이면 상대는 같은 조 최강팀이다(이번에는 포르투갈). 무조건 이기고 봐야 하는데 막상 뚜껑을 열어보면 '어라?' 의외로 잘 한다. 비기거나 심지어는 1점 차로 이기기도 한다.
  • 하지만 그 지긋지긋한 '경우의 수' 때문에 골득실에서 뒤져서 16강 진출 실패! 탄식과 자조, 개운치 않은 뒷맛을 남기며 4년 후를 기약하곤 했다.
로딩 중...

서울신문

이번에는 달랐다. 내 기억으로 월드컵 본선 무대에서는 한 번도 우리 손을 들어주지 않던 '경우의 수' 징크스가 이번에는 우리를 향해 미소 지었다. 빌드업 축구의 완성도가 높아졌고 투지만큼은 세계 톱 클래스였던 것 같다. 누구 말처럼 공은 둥글고 월드컵에서는 어떤 일이든 일어날 수 있다. 상대가 브라질이든 그 할아버지든 마찬가지다. 남은 경기는 '덤'이라 생각하고 후회 없는 승부를 펼쳤으면 한다.

(PS) 우리 경기 마치고 남의 나라 경기까지 이렇게나 가슴 졸이며 본 적이 있었나 싶다. 두 경기 보고나니 어깨가 다 아프다. 일각이 여삼추라는 말이 이래서 생겼구나, 실감할 수 있는 순간이었다.

권현욱(엑셀러)
저자: 권현욱(엑셀러), 아이엑셀러 대표

필자는 Excel 컨설턴트, 작가, 그리고 크리에이터입니다. 현재 Microsoft Excel MVP이며, 『챗GPT+엑셀 업무자동화 정석』을 비롯한 10여 권의 도서를 집필했습니다. Excel 자동화 및 생산성 향상 분야에서 25년 넘는 경력을 보유하고 있습니다.

권현욱(엑셀러) 님의 최신 포스트:
  • 최신 글을 불러오는 중...


이 글은 멤버십 회원 우선 공개 콘텐츠입니다. 전체 대상으로는 일주일 후 공개됩니다(작성일 기준).
26년 경력 Microsoft MVP 권현욱(엑셀러) 대표 직강 1강 무료

🎁 파워툴스 마스터클래스 · 엑셀 바이브 코딩

AI에게 말로 지시해서 '나만의 엑셀 도구'를 만들고 리본에 장착합니다.

  • 코딩 지식 없이 시작 · 코드는 AI가 작성
  • 엑셀 리본에 내 탭과 버튼을 만들고 XLAM으로 공유
  • 1강 무료 수강 가능
수강 신청하기 강의 소개 보기

최장 연승 기록 집계하기

핵심 요약: 엑셀 VBA로 연승 기록 자동 체크하기

회원별 승/패 기록표에서 최장 연승 횟수를 세고 하이라이팅까지 한 번에 처리하는 VBA 코드입니다. 수식으로는 길고 복잡해지거나 불가능한 작업을, 아래 5단계로 나눠 접근하면 쉽게 이해할 수 있습니다.

  • 준비 단계: 변수를 선언하고, Offset과 Resize 메서드로 대진 결과표의 본문 영역만 정확히 지정합니다.
  • 서식 초기화: 이전 실행에서 지정한 배경색과 글자색을 되돌리고, 연승 기록을 입력할 열을 정리합니다.
  • 승리 구간 수집: For Each 순환문을 두 번 중첩해 행과 셀을 차례로 돌며, 'O'가 이어지는 구간을 Resize로 넓히고 Union으로 하나의 영역에 모읍니다.
  • 최장 연승 찾기: Areas 컬렉션으로 각 승리 구간의 크기를 비교해 가장 긴 연승 구간을 찾고, 승리 내역은 빨간 굵은 글씨로 표시합니다.
  • 결과 표시: 최장 연승 구간은 빨간 배경에 흰 글씨로 강조하고, 연승 횟수를 N열 쪽 '연승 기록' 열에 자동으로 입력합니다.

질문 하나 & 완성 예

아이엑셀러에서 열심히 공부하는 어느 분의 질문입니다. 아마도 테니스 동호회에서 총무 역할을 담당하시나 봅니다. 질문 내용을 요약하면 이렇습니다.

각 회원 별로 10게임씩 경기를 하며 경기마다 승/패를 기록한 시트가 있습니다. N열에는 회원 별로 몇 연승했는지 기록하고 싶다는 겁니다. 지금까지는 매번 일일이 카운팅해서 입력하고 있는데 이걸 간단히 해결할 방법이 없을까 하는 질문입니다.

로딩 중...

질문 내용

수식으로도 가능은 해 보입니다만 아주 길고 복잡한 수식이 될 것 같습니다. 그런 수식을 만들 노력과 정성이라면 VBA로 코딩하는 것이 한결 편리하고 효율적이리라 생각합니다. '연승기록' 시트에서 '연승 기록 체크' 버튼을 클릭하면 원하는 대로 결과가 나옵니다.

로딩 중...

완성 예

뿐만 아니라 승리 내역(O)에는 빨간 글자색으로, 연승 기록에는 빨간 배경색에 흰 글씨로 하이라이팅 표시되어 있습니다. 이런 것은 함수로는 도저히 할 수 없는 일이지요.

코드 작성

워크시트에서 ALT + F11 키를 눌러서 Visual Basic Editor 창을 엽니다. VB Editor에서 [삽입] - [모듈] 메뉴를 선택하여 모듈Module을 삽입하고 코드를 작성합니다. 코드에 대한 자세한 설명은 이어서 나옵니다. 길고 복잡한 코드라도 나누고 쪼개어(같은 말이네...) 접근하면 이해하기 쉬워집니다.


Sub successiveWin()
  ''' ---------- (1단계) ----------
  Dim shtX As Worksheet
  Dim rTbl As Range
  Dim rAreas As Range
  Dim rArea As Range
  Dim rA As Range
  Dim rWin As Range
  Dim rRow As Range
  Dim rX As Range
  
  On Error Resume Next
  Set shtX = Worksheets("연승기록")
  Set rTbl = shtX.Range("myTable").CurrentRegion
  Set rTbl = rTbl.Offset(1, 1).Resize(rTbl.Rows.Count - 1, rTbl.Columns.Count - 1)
  
  ''' ---------- (2단계) ----------
  With rTbl
      .Interior.ColorIndex = xlNone
      .Font.ColorIndex = 1
      With .Cells(.Columns.Count)
          .Offset(, 2).CurrentRegion.Clear
          .Offset(, 2).EntireColumn.HorizontalAlignment = xlCenter
          .Offset(-1, 2) = "연승 기록"
      End With
  End With

  ''' ---------- (3단계) ----------
  For Each rRow In rTbl.Rows
      For Each rX In rRow.Cells
          If rX = "O" Then
              If rArea Is Nothing Then
                  Set rArea = rX
              Else
                  Set rArea = rArea.Resize(, rArea.Cells.Count + 1)
              End If
          Else
KKK:
              If rAreas Is Nothing Then
                  Set rAreas = rArea
              Else
                  Set rAreas = Union(rAreas, rArea)
              End If
              Set rArea = Nothing
          End If
      Next
      If Not rArea Is Nothing Then GoTo KKK
      
  ''' ---------- (4단계) ----------
      For Each rA In rAreas.Areas
          rA.Font.ColorIndex = 3
          rA.Font.Bold = True
          If rWin Is Nothing Then
              Set rWin = rA
          Else
              If rWin.Cells.Count <= rA.Cells.Count Then Set rWin = rA
          End If
      Next
      
  ''' ---------- (5단계) ----------
      rWin.Interior.ColorIndex = 3
      rWin.Font.ColorIndex = 2
      rRow.Cells(rRow.Cells.Count).Offset(, 2) = rWin.Cells.Count
      Set rWin = Nothing
      Set rAreas = Nothing
  Next
End Sub
          

CODE

코드 해설

1. 첫 번째 단계는 변수를 선언하고 필요한 값이나 영역을 지정하는 작업입니다.


Dim shtX As Worksheet    ''' 워크시트 개체에 접근할 변수
Dim rTbl As Range        ''' 대진 결과표에 접근할 변수
Dim rAreas As Range      ''' 승리(O)한 영역 전체에 접근할 변수
Dim rArea As Range       ''' 승리한 영역에 개별적으로 접근할 변수
Dim rA As Range          ''' 승리 영역에 접근할 순환 변수
Dim rWin As Range        ''' 최장 연속 승리 영역에 접근할 변수
Dim rRow As Range        ''' 대진 결과표의 행 단위로 접근할 변수
Dim rX As Range          ''' 개별 셀에 접근할 순환 변수

On Error Resume Next     ''' 실행 도중 오류가 발생하더라도 다음 명령 수행
Set shtX = Worksheets("연승기록")
Set rTbl = shtX.Range("myTable").CurrentRegion    
                        ''' myTable의 인접 영역을 rTbl 변수에 할당
Set rTbl = rTbl.Offset(1, 1).Resize(rTbl.Rows.Count - 1, rTbl.Columns.Count - 1)
                        ''' 대진 결과표의 본문 영역을 rTbl 변수에 할당
          

해설

2. 대진 결과표의 서식을 초기화합니다.


With rTbl
  .Interior.ColorIndex = xlNone        ''' 셀 배경색 초기화
  .Font.ColorIndex = 1                 ''' 글자색 검정색으로 지정
  With .Cells(.Columns.Count)
      .Offset(, 2).CurrentRegion.Clear ''' 연승 내역을 기록할 주변 영역 지우기
      .Offset(, 2).EntireColumn.HorizontalAlignment = xlCenter
      .Offset(-1, 2) = "연승 기록"
  End With
End With
          

해설

3. For Each ~ In ~ Next 문을 두 번 중첩합니다. 바깥쪽 순환문은 테이블의 행 단위로, 안쪽 순환문은 각 행의 셀 단위로 접근합니다. 이곳이 전체 코드의 핵심입니다. rArea와 rAreas 변수에 어떤 영역이 이미 할당되어 있는지 아닌지 여부에 따라 새로운 영역을 업데이트 해주는 부분을 눈여겨 보시기 바랍니다.


For Each rRow In rTbl.Rows        ''' 테이블의 개별 행 단위로 접근
For Each rX In rRow.Cells       ''' 개별 행의 각 셀 단위로 접근
    If rX = "O" Then            ''' 셀 값이 O(승리)라면...

      ''' rArea 변수에 아무 것도 할당되어 있지 않다면 rX를,
      ''' 이미 어떤 영역이 할당되어 있다면 다음 셀까지로 범위 확장
      If rArea Is Nothing Then
            Set rArea = rX
        Else
            Set rArea = rArea.Resize(, rArea.Cells.Count + 1)
        End If
    Else
KKK:
        ''' rAreas 변수에 아무 것도 할당되어 있지 않다면 rArea 변수 값을,
        ''' 이미 어떤 영역이 할당되어 있다면 기존 rAreas 영역과 rArea 영역 통합
        If rAreas Is Nothing Then
            Set rAreas = rArea
        Else
            Set rAreas = Union(rAreas, rArea)
        End If
        Set rArea = Nothing               ''' rArea 변수 초기화
    End If
  Next
If Not rArea Is Nothing Then GoTo KKK    ''' 마지막 rArea 영역을 처리하기 위해 KKK 레이블로 이동
          

해설

4. 승리한 셀이 담긴 영역에 접근하여 서식을 지정합니다. 또한 rWin과 rA 영역을 비교하여 가장 긴 연승 기록에 해당하는 영역을 rWin 변수에 담아둡니다.


For Each rA In rAreas.Areas         ''' rAreas의 각 영역(Area)에 접근
  rA.Font.ColorIndex = 3            ''' rA, 즉 값이 O인 셀의 글자색을 빨간색으로 지정
  rA.Font.Bold = True               ''' 굵은 글꼴로 지정

  ''' rWin 변수에 아무 것도 할당되어 있지 않다면 rA 변수 값을,
  ''' 이미 어떤 영역이 할당되어 있다면 rWin과 rA 영역의 크기를 비교하여 큰 영역을 rWin 변수에 할당
  If rWin Is Nothing Then        
      Set rWin = rA
  Else
      If rWin.Cells.Count <= rA.Cells.Count Then Set rWin = rA
  End If
Next
          

해설

여기까지 진행되었다면 테이블의 첫 번째 행에 대한 처리가 끝납니다. 그 결과는 아래 그림과 같습니다. 셀 값이 O라면 굵은 빨간색으로 표기해 줍니다. 빨간 점선으로 표기한 영역이 각각의 rA에 해당합니다.

로딩 중...

5. 마지막으로, 가장 긴 연승 기록 영역에 서식을 지정합니다.


rWin.Interior.ColorIndex = 3      ''' 셀 배경색을 빨간색으로 지정
rWin.Font.ColorIndex = 2          ''' 글자색을 흰색으로 지정
rRow.Cells(rRow.Cells.Count).Offset(, 2) = rWin.Cells.Count    
                  ''' 각 행의 가장 오른쪽 셀에서 2열 더 오른쪽으로 이동하여 연승 기록 삽입
Set rWin = Nothing                ''' rWin 변수 초기화
Set rAreas = Nothing              ''' rAreas 변수 초기화
Next
          

해설

중첩 For ~ Next 문이 사용되어 처음 보면 좀 복잡해 보일 수 있습니다만 VBA 디버깅 툴을 이용하여 진행 과정을 몇 차례 추적해 보면 이해하시리라 생각합니다. 이와 관련해서는 다음 강의를 참고하세요.