<엑셀VBA 입문 8강> 셀 내용 가져오기

<엑셀VBA 입문 8강> 셀 내용 가져오기

오늘 배울 내용은 셀 내용을 가져오는 VBA 코드입니다.

내용은 생각보다 어려울 수 있습니다만, 제대로 배워두면 정말 도움이 되는 코드입니다.

VBA만 생각할게 아니라, 코딩의 기초를 쌓는다고 생각하면 정말 좋은 예제입니다.

(읽어보고 정 어렵다면 함수째로 복사해서 사용하면 됩니다.)

1. 셀 1개의 내용값 가져오기

아래와 같은 시트가 있다고 합시다.

B2에 “어떤 단어”라는 텍스트가 입력되어 있습니다.

이 내용을 (커서가 위치한) D6에 그대로 표시하고 싶다면 어떻게 해야할까요?

B2의 내용이 바뀔 때마다 D6의 내용도 똑같이 바뀌게 하고 싶다면 말입니다.

아시다시피 아래처럼 “=B2” 라고 입력하면 됩니다.

하지만 VBA 함수를 쓰고 싶다면요?

물론 이와 같은 경우에 굳이 VBA 함수를 쓸 필요가 없습니다만, 기본이 되는 함수를 잘 만들어두면 두고두고 유용하게 쓸 수 있습니다.

나중에 알게 됩니다.

아래와 같이 getContent라는 함수를 만들어봅니다.

매개변수가 보이시나요? 매개변수가 뭐냐고요? 참고로 매개변수란, 함수(Function) 에 넘겨줘야 하는 인자값을 말합니다. <매개변수>, <파라미터>, <인자값>, <아규먼트>… 모두 같은 말입니다. 함수는 항상 Function 함수명(매개변수1, 매개변수2, 매개변수3 …) 형태가 됩니다.

이제 매개변수가 보일겁니다. cell 이 매개변수입니다. 뒤에 As Range 라고 붙은게 있는데, 형식을 정해준겁니다. As 뒤에 붙는 이런것을 <변수형(변수의 타입)>이라고 합니다. 굳이 As Range를 붙이지 않아도 상관없지만 이렇게 명시적으로 형식을 지정해주면 장점이 2가지 있습니다. 장점 하나, 코드를 다 읽지 않아도 어떤 타입의 변수가 필요한지 알 수 있습니다. 장점 둘, 자동완성이 지원됩니다.

참고로 자동완성이란 변수 뒤에 점(.)을 찍거나, Ctrl + Space 를 누르면 나타나는 콤보박스를 말합니다. 변수형을 지정해주면 좀 더 쓸만한 자동완성이 지원됩니다. 자동완성은 제가 임의로 붙인 말이고, 영어로는 어시스트라고 부르는 것 같군요.

위의 그림이 자동완성(영어로는 어시스트)을 요약해놓은 겁니다. 한 번 읽어보시구요.

다시 getContent 함수로 돌아가보면, 아래 내용입니다.

Function getContent(cell As Range)
    resultVal = Range(cell, cell).Value
    getContent = resultVal
End Function

매개변수로 넘어온 cell 변수를 이용해서 해당 셀의 value를 가져오고 있습니다. Range(셀, 셀).Value 라는 명령어를 통해서요.

사실 실험해보시면 아시겠습니다만 Range함수는 Range(“A1”, “A1”).Value 이런식으로 쓰면 됩니다.

val = Range(“A1”, “A1”).Value 라고 쓰면 A1 셀의 내용값이 변수 val에 대입됩니다.

다만 Range(“A1”, “A2”).Value 같은 경우 먹통이 됩니다. 여러 개의 셀에는 통하지 않는거죠. 여러 개 셀의 내용(Value)를 가져오려면 코딩을 제법 해야됩니다.

2. 셀 n개의 내용값 가져오기


만약 아래와 같은 시트가 있다고 합시다.

 

여러 셀에 여러 단어가 나뉘어 입력되어 있습니다. B2 셀에 “여러”, C2 셀에 “문장을”, B3 셀에 “최대한”, B4 셀에 “합쳐 봅니다”라고 적혀있네요.

이걸 이어붙여서 한 셀에 표현하려면 어떻게 해야할까요?

엑셀 좀 하시는 분들 아실텐데 CONCATENATE 라는 함수가 있어요. 해보시면 아시겠지만 =CONCATENATE(B2, C2, B3, B4) 이런식으로 씁니다. 근데 이 함수 자체가 그다지 쓸모없어요.

저같으면 =B2 & C2 & B3 & B4 이렇게 이어버립니다. 함수 안쓰고 똑같은 효과죠.

VBA로 구현하면 조금 어렵습니다.

앞서도 말씀드렸지만 이걸 굳이 VBA로 구현할 필요가 없어보이지만, 나중을 위해 배워봅시다.

일단 셀의 값은 1개씩 가져올 수 밖에 없습니다. Range(“A1”, “A1”).Value 방식입니다. 똑같은 효과를 낼 수 있는게 Cells(1, 1).Value 라는 명령어가 있습니다. Cells(행, 열).Value 입니다. 즉, 아래와 같이 이해해보세요.

Range(“A1”, “A1”).Value 는 Cells(1, 1).Value 와 같음.

Range(“A2”, “A2”).Value 는 Cells(2, 1).Value 와 같음.

Range(“B1”, “B1”).Value 는 Cells(1, 2).Value 와 같음.

Range(“C3”, “C3”).Value 는 Cells(3, 3).Value 와 같음.

VBA에서 for문이나 do-loop 문을 돌리기 위해서는 아무래도 문자보다 숫자가 편합니다. 다시 말해서 (“A1”, “A1”) 보다는 (1, 1) 이 더 다루기 편합니다. 따라서 Cells(행, 열) 명령어를 자주 쓰게 될겁니다. 기억해두세요.

여러 셀의 내용을 가져오기 위해서는 일단 매개변수로 범위를 받아야 합니다. 엑셀의 범위는 항상 직사각형 형태를 취하는데요. 테트리스처럼 이가 빠진 모양은 될 수가 없고 항상 직사각형 모양입니다. 다시 말해서 B2 & C2 & B3 & B4 이런 범위는 없습니다. 범위는 B2:C4 이런식입니다.

이제부터 함수를 구상 해보겠습니다.

1. 매개변수로 범위를 받는다. (범위는 셀 1개일 경우 “A1” 이런식이 된다. 셀 n개일 경우 “B2:C4” 이런식이 된다)

2. 범위에 콜론(:)이 있을 경우 n개로 판단하고, 콜론(:)이 없을 경우 1개로 판단한다.

3-1. n개일 경우 직사각형 범위에 해당하는 모든 셀의 Value를 이어붙여서 리턴하자. 예컨대 범위가 B2:C4일 경우, Cells(2, 2).Value 부터 Cells(4, 3).Value 를 다 이어붙여서 리턴하자.

3-2. 1개 일 경우 1개 셀의 Value를 리턴하자. 예컨대 Range(“A1″:”A1”).Value 의 값을 리턴하자.

결과적으로 코드는 아래와 같습니다.

Function getContent(cell As Range)
    Dim resultVal
    resultVal = “”
   
    ‘addr 변수에 문자열을 저장한다. $가 포함되어 있다면 제거한다.
    ‘ex) cell.Address = “$A$1:$D$10” 이라면 addr = “A1:D10” 이 된다.
    ‘ex) cell.Address = “$A$1” 이라면 addr = “A1” 이 된다.
    Dim addr
    addr = cell.Address & “”
    addr = Replace(addr, “$”, “”)
   
    Dim colonIdx
    colonIdx = InStr(addr, “:”)
    If colonIdx > 0 Then
        ‘콜론이 존재하는 경우(다중범위)
        Dim leftAddr, leftColNum, leftRowNum
        leftAddr = Mid(addr, 1, colonIdx – 1)
        leftColNum = Range(leftAddr).Column
        leftRowNum = Range(leftAddr).Row
       
        Dim rightAddr, rightColNum, rightRowNum
        rightAddr = Mid(addr, colonIdx + 1, Len(addr) – colonIdx)
        rightColNum = Range(rightAddr).Column
        rightRowNum = Range(rightAddr).Row
       
        For r = leftRowNum To rightRowNum
            For c = leftColNum To rightColNum
                resultVal = resultVal & Cells(r, c).Value
                ‘MsgBox (“(” & r & “,” & c & “) : ” & Cells(r, c).Value)
            Next c
        Next r
       
        getContent = resultVal
    Else
        ‘콜론이 존재하지 않는 경우(단일범위)
        resultVal = Range(cell, cell).Value
        getContent = resultVal
    End If

End Function

함수가 상당히 길고 어렵다고 느낄 수 있는데, 처음엔 그럴 수 있습니다.

한 줄씩 이해하는게 가장 좋은 방법입니다. 정 어렵거나 시간이 부족하면 함수 통째로 복사-붙여넣기해다가 잘 사용하면 됩니다.

굉장히 유용한 명령어들이 많이 나오게 되는데요. 하나씩 살펴보겠습니다. 복습 차원에서 한 번 봤던 명령어도 간단히 짚고 갑니다.

1. Dim

변수를 선언하는 명령어입니다.

Dim a

a = “문자열”

이런식으로 씁니다.

2. Range형 객체의 Address 변수

(참고로 객체는, 변수와 함수를 갖고 있는 것을 말합니다. 아직은 잘 몰라도 됩니다.

Dim cell As Range 식으로 선언 하면 됩니다.)

Range형 객체의 Address 변수는 “$A$1” 이나, “$A$1:$B$2” 형태의 값을 갖고 있습니다. 예컨대 cell이 Range형 객체일 때, cell.Address 형식으로 사용합니다. 1개 셀일 때는 “$A$1” 형태의 값이고, n개 셀일 때는 “$A$1:$B$2” 형태의 값입니다.

3. &[앤드] 기호

&[앤드] 기호는 문자열 결합에 사용합니다. 숫자는 +[플러스] 기호를 써서 덧셈하는 반면, 문자열은 &[앤드] 기호로 이어붙이기를 합니다. 따라서 숫자변수 + 숫자변수는 숫자변수가 되지만, 숫자변수 & 문자변수는 문자변수가 됩니다.

참고로 &[앤드] 기호는 숫자의 문자열화(문자열로 변환) 용도로도 쓰이곤 합니다. 꼭 숫자 뿐 아니라, 문자인지 숫자인지 긴가민가한 변수를 문자열화(문자열로 변환)하는 용도로도 쓰입니다. 아래 예제를 보세요.

‘숫자변수 선언

Dim num

num = 3

‘문자열로 변환

Dim strNum

strNum = num & “”

4. Replace 함수

치환 함수. Raplace(대상문자열, 바꿀값, 새값) 형식으로 씁니다. addr = Replace(addr, “$”, “”) 이렇게 쓰면 문자열에 있는 “$”가 모두 공백으로 치환됩니다.

5. InStr 함수

위치값 계산함수. InStr(대상문자열, 찾는값) 형식으로 씁니다. 예를 들어 1이 나오면 문자열 첫번째 위치에 찾는값이 존재하는 겁니다. 1 미만(=0 이하)가 나오면 찾는값이 문자열 내에 존재하지 않는 겁니다.

6. Mid 함수

문자열 자르기 함수. Mid(대상문자열, 시작위치, 글자수) 형식으로 씁니다. 참고로 첫번째 글자의 인덱스값(위치값)이 1 입니다. 예를 들어 “대한민국”이라는 문자열이 있을 때 “대”가 인덱스 1, “한”이 인덱스 2, “민”이 인덱스 3, “국”이 인덱스 4입니다. “민국”만 자르려면 val = Mid(“대한민국”, 3, 2) 식으로 쓰면 됩니다.

상당히 헷갈릴 겁니다. 이 함수는 헷갈리는게 정상입니다. 종이나 그림판에 원고지(?) 그려가면서 천천히 살펴가면서 사용하시면 됩니다. 시간 갖고 차분히 보시면 됩니다.

7. Range(특정셀).Column

특정셀의 컬럼(열)을 숫자값으로 리턴합니다. 예를 들어 Range(“A1”).Column 의 값(컬럼값)은 1입니다.

8. Range(특정셀).Row

특정셀의 로우(행)을 숫자값으로 리턴합니다. 예를 들어 Range(“A1”).Row 의 값(로우값)은 1입니다.

9. 함수명 = 값

함수명 = 값 식으로 쓰면 값을 리턴합니다. 에를 들어 Function aaa(): aaa = “123”: End Function 이라는 함수가 있을 경우, Dim tmp: tmp = aaa() 라고 쓰면 tmp 에 “123”값이 대입됩니다.

10. Cells(행숫자, 열숫자).Value

시트의 특정 셀 값을 가져오는 코드. 예를 들어 행숫자 1에 열숫자 1일 경우 A1의 값을 가져옵니다.

결과적으로 getContent 함수를 적용하면 아래와 같은 결과를 볼 수 있습니다.

 

이어지는 글 <엑셀VBA 입문 9강> 특정 단어의 개수를 세는 방법 : https://blog.naver.com/bb_/221266831714

이어지는 글 <엑셀VBA 입문 10강> VBA로 웹파싱하기 (HTML소스 가져오기)  : https://blog.naver.com/bb_/221267721181
이어지는 글 <엑셀VBA 입문 11-2강> 배열(Array) : https://blog.naver.com/bb_/221313490342