<엑셀VBA 입문 13강> 선택영역 한꺼번에 변경하기(VBA Selection)
점심에 친구로부터 전화가 걸려왔다. 엑셀 시트에 적힌 숫자들을 모두 -1 시켜야하는데, 그렇게 처리할 파일이 무척 많다고 했다. VBA를 알면 쉽게 끝날 일이지만, 모르면 노가다로 고생할 일이다.
VBA를 모른다길래 단축키를 누르면 셀 값을 -1 시키고 커서를 한줄 아래로 이동시키는 코드를 짜줬다. 조금 써보더니 불편하다고, 드래그해서 선택한 여러 셀의 값을 한번에 고치는 방법은 없느냐고 했다. 물론 있다.
오늘은 선택한 영역의 값을 한꺼번에 수정하는 방법을 알아본다. 무척 유용한 코드가 될 것이다.
1. 함수 추가 (getLeft 함수, getRight 함수, makeRangeText 함수)
우선 아래 3개의 함수를 그대로 갖다 쓰기로 한다. 필자가 직접 짠 코드이고, 그대로 복사해다가 쓰면 된다. getLeft 함수, getRight 함수, makeRangeText 함수 이렇게 3가지이다.
코드는 아래와 같다.
(다 들여다보기엔 많으니 내용은 스킵해도 좋다. 잘 갖다쓰기만 하면 된다.)
|
‘getLeft : 문자열에서 특정 문자 좌측값을 잘라 가져온다. ‘ex) text가 “ab1cd”이고 mark가 “1”일 경우, “ab”를 리턴한다. Function getLeft(text, mark) ‘대상 텍스트가 빈값일 경우 빈값 리턴 If Len(text) = 0 Then getLeft = “” Exit Function End If ‘마크가 빈값일 경우 그대로 리턴 If Len(mark) = 0 Then getLeft = text Exit Function End If Dim markIndex markIndex = InStr(1, text, mark) If markIndex > 0 Then ‘마크가 존재할 경우 좌측 문자열 리턴 Dim leftText leftText = Mid(text, 1, markIndex – 1) getLeft = leftText Exit Function Else ‘마크가 존재하지 않을 경우 그대로 리턴 getLeft = text Exit Function End If End Function
‘getRight : 문자열에서 특정 문자 우측값을 잘라 가져온다. ‘ex) text가 “ab1cd”이고 mark가 “1”일 경우, “cd”를 리턴한다. Function getRight(text, mark) ‘대상 텍스트가 빈값일 경우 빈값 리턴 If Len(text) = 0 Then getRight = “” Exit Function End If ‘마크가 빈값일 경우 그대로 리턴 If Len(mark) = 0 Then getRight = text Exit Function End If Dim markIndex markIndex = InStr(1, text, mark) If markIndex > 0 Then ‘마크가 존재할 경우 우측 문자열 리턴 Dim rightText rightText = Mid(text, markIndex + Len(mark), Len(text) – markIndex) getRight = rightText Exit Function Else ‘마크가 존재하지 않을 경우 그대로 리턴 getRight = text Exit Function End If End Function
‘makeRangeText : 현재 선택한 셀을 “행값,열값~행값,열값” 형태의 문자열로 리턴한다. ‘ex1) 1개 셀(A1) 선택한 경우 -> “1,1~1,1” 리턴 ‘ex2) 1개 셀(G3) 선택한 경우 -> “3,7~3,7” 리턴 ‘ex3) n개 셀(G3~I5) 선택한 경우 -> “3,7~5,9” 리턴 Function makeRangeText() Dim addr addr = Selection.Address ‘범위에 달러 있는 경우 제거한다 If InStr(1, addr, “$”) > 0 Then addr = Replace(addr, “$”, “”) End If
Dim result
Dim colonIndex colonIndex = InStr(1, addr, “:”) If colonIndex > 0 Then ‘n개 셀 선택(콜론이 있는 경우) Dim leftAddr Dim rightAddr leftAddr = getLeft(addr, “:”) rightAddr = getRight(addr, “:”) result = Range(leftAddr).row & “,” & Range(leftAddr).Column & “~” & Range(rightAddr).row & “,” & Range(rightAddr).Column Else ‘1개 셀 선택(콜론이 없는 경우) result = Range(addr).row & “,” & Range(addr).Column & “~” & Range(addr).row & “,” & Range(addr).Column End If
makeRangeText = result End Function
|
함수에 관해 간략히 설명하자면 getLeft 함수는 특정 문자열의 좌측값을 가져오는 함수다. 예를 들어 getLeft(“대상문자열”, “문”)이라고 쓰면 리턴값은 “대상”이다.
반면 getRight는 우측값을 가져온다. 예를 들어 getRight(“대상문자열”, “문”)이라고 쓰면 리턴값은 “자열”이다.
마지막으로 makeRangeText 함수는 조금 특이하다. 현재 선택한 범위를 문자열로 리턴해주는데, “행값,열값~행값,열값” 형식으로 리턴한다. 예를 들어서 셀(A1) 1개를 선택한 경우, “1,1~1,1” 이라는 문자열을 리턴한다. 셀(G3~I5) 이렇게 여러 개의 셀을 선택한 경우, “3,7~5,9” 를 리턴한다.
한마디로 셀 1개가 선택되어 있든, 드래그해서 셀 100개가 선택되어 있든 “행값,열값~행값,열값” 형식으로 리턴해준다. 굳이 “A1″을 “1,1”로 바꾸는 이유는, 각 숫자를 이용해서 쉽게 for문을 돌리기 위해서다. 나중에 보게 되겠지만 Cells(행값, 열값).Value 명령어로 특정 셀의 값을 가져올 수 있다. (여기서 행값, 열값은 숫자값이다.)
2. 메인코드 작성 (선택영역의 값을 모두 “1”로 일괄변경)
메인코드는 아래와 같이 작성한다.
|
Sub 매크로1() ‘ ‘ 매크로1 매크로 ‘ ‘ 바로 가기 키: Ctrl+e ‘
‘makeRangeText : 현재 선택한 셀을 “행값,열값~행값,열값” 형태의 문자열로 리턴한다. ‘ex) n개 셀(G3~I5) 선택한 경우 -> “3,7~5,9” 리턴 Dim rangeText rangeText = makeRangeText()
‘물결(~)을 기준으로 좌측주소값과 우측주소값으로 자른다. ‘ex) n개 셀(G3~I5) 선택한 경우 -> leftAddr 은 “3,7” 이 되고, rightAddr 은 “5,9” 가 됨 Dim leftAddr Dim rightAddr leftAddr = getLeft(rangeText, “~”) rightAddr = getRight(rangeText, “~”)
‘쉼표(,)를 기준으로 각 주소값을 행값과 열값으로 자른다. ‘ex) n개 셀(G3~I5) 선택한 경우 -> leftRow 은 “3”, leftCol 은 “7”, rightRow 는 “5”, rightCol 은 “9” 가 됨 Dim leftRow Dim leftCol Dim rightRow Dim rightCol leftRow = getLeft(leftAddr, “,”) leftCol = getRight(leftAddr, “,”) rightRow = getLeft(rightAddr, “,”) rightCol = getRight(rightAddr, “,”)
‘선택영역의 좌측 상단셀부터 우측 하단셀까지, 반복문을 돌며 각 셀을 처리한다. For r = leftRow To rightRow For c = leftCol To rightCol
‘선택한 셀의 값을 “1”로 변경 Cells(r, c).Value = “1” Next c Next r
End Sub
|
자칫 복잡하게 보일 수 있는 내용을 따로 함수로 만들었으므로(getLeft, getRight, makeRangeText) 이해하기 어렵지 않을 것이다.
현재 상기 코드는 Ctrl + e 키를 누를 경우 선택영역(커서가 위치한 1개의 셀 혹은 드래그한 여러개의 셀)의 값이 “1”로 변경되는 내용이다.

<여러 개의 셀을 선택한 상태에서 Ctrl + e 키를 누르면 값이 일괄 바뀐다>
3. 메인코드 개선 (선택영역의 값을 -1 처리)
메인코드를 약간 개선하면, 선택영역의 값 뒤에 특정한 문자열값을 붙이는 것도 가능하고, if문을 사용하면 일종의 조견표 처리도 가능하다. 예를 들면 “사자”, “호랑이”, “곰”은 “동물”로 바꾸고, “잡초”, “선인장”, “은행나무”는 “식물”로 바꾼다던지 말이다.
여기서는 선택영역의 값을 -1 처리하는 코드로 만들어보자.
마지막 부분을 아래와 같이 고치면 된다.
|
Sub 매크로1()
(중략)
‘선택영역의 좌측 상단셀부터 우측 하단셀까지, 반복문을 돌며 각 셀을 처리한다. For r = leftRow To rightRow For c = leftCol To rightCol Dim oneVal oneVal = Cells(r, c).Value
‘숫자일 경우만 동작 If checkIsNumber(oneVal) Then ‘현재값에서 -1 처리 Cells(r, c).Value = oneVal – 1 End If Next c Next r
End Sub
|
보다시피 셀값이 숫자인 경우에만 -1 처리하는 코드이다.
이 때 셀값이 숫자인지 체크하는 함수인 checkIsNumber 함수가 필요한데, 단순무식하게 만들어보았다.
|
‘checkIsNumber : 문자열이 숫자인지 체크해서, 숫자일 경우 1을 리턴한다. ‘0 또는 자연수만 체크가능하다. 마이너스(음수) 또는 소수점이 있는 숫자는 해당없음. Function checkIsNumber(str)
Dim strLen strLen = Len(str) If strLen = 0 Then checkIsNumber = 0 Exit Function End If Dim oneChar For i = 1 To strLen oneChar = Mid(str, i, 1) If oneChar <> “0” And oneChar <> “1” And oneChar <> “2” And oneChar <> “3” And oneChar <> “4” And oneChar <> “5” And oneChar <> “6” And oneChar <> “7” And oneChar <> “8” And oneChar <> “9” Then checkIsNumber = 0 Exit Function End If Next i checkIsNumber = 1 End Function
|
정상적으로 작성되었다면, 마우스로 여러셀을 드래그해서 선택한 후, Ctrl + e 키를 누르면 0 이상의 숫자값에 한해서 -1 처리될 것이다. 전체 코드는 첨부파일로 넣어두겠다.
해당 코드를 사용하려면 VBA 윈도우 띄우기(엑셀에서 Atl + F11) -> 상단 메뉴의 [파일] – [파일 가져오기] – [180621.bas] 선택하고 엑셀에서 Ctrl + e 키를 눌러보면 된다.
이어지는 글 <엑셀VBA 입문 14강> On Error 구문의 사용 : https://blog.naver.com/bb_/221329746966
이어지는 글 <엑셀VBA 입문 15강> 텍스트 파일쓰기, 파일읽기 : https://blog.naver.com/bb_/221329757129
이어지는 글 <엑셀VBA 입문 16강> VBA로 워크시트 함수 활용하기 : https://blog.naver.com/bb_/221350410698