EXCEL - VBA

두 문장의 같은 단어 비교(1) - 매크로 작성

별동산 2023. 5. 8. 08:14
반응형

위와 같이 A1셀과 A2셀의 문장 2개를 비교해서 같은 단어일 경우는 글자 색을 빨간색으로 표시하는 것을 해보겠습니다.
 

문장비교.xlsx
0.01MB

 
 
 

1. 논리

A1셀과 A2셀을 각각 빈칸을 기준으로 문장을 나눈 다음 배열에 넣고, 배열끼리 비교해서 배열이 같을 때, 여기서는 포함될 때를 기준으로 판단하려고 합니다. 다시 말해 '국민'은 '국민의'에 포함되므로 같은 것이 되고, '국민의'와 '국민을'은 포함관계가 아니기 때문에 다른 것이 됩니다.
 
어간을 기준으로 비교하면 되는데, 그것이 어려워서 조건으로 못 넣었습니다.
 
 

2. 매크로 작성

 
아래와 같이 Sub 프로시저와 Function 프로시저로 구성되어 있습니다.
 
가. Sub 프로시저
compare_sentence(문장 비교), font_red(일치하는 배열의 글자색을 빨간색으로 변함), font_black(A1셀과 A2셀의 글자색을 검은색으로 바꿈) 3개
 
나. Function 프로시저
location_array_num(배열의 순번 찾기) 1개
 
다. 소스

Option Explicit

Sub compare_setence()
    'A1과 A2셀의 문장을 공백으로 구분한 문자를 저장하기 위한 배열
    Dim testArray1() As String, testArray2() As String
    
    'len1, len2는 배열의 크기를 저장, i, j는 배열 이동을 위한 변수
    Dim len1 As Integer, len2 As Integer, i As Integer, j As Integer
    
    ' 화면 갱신하지 않음
    Application.ScreenUpdating = False
    
    ' A1셀을 공백을 기준으로 구분해서 testArray1, testArray2 배열에 저장
    ' 공백인 경우를 제외하여 배열 축소
    testArray1 = Split(Range("a1"))
    testArray2 = Split(Range("a2"))
        
    ' testArray1, testArray2의 배열 크기를 len1, len2에 저장
    len1 = UBound(testArray1)
    len2 = UBound(testArray2)
    
    
    ' testArray1 배열을 하나씩 이동하면서 처리
    For i = 0 To len1
    
        ' testArray2 배열을 하나씩 이동하면서 처리
        For j = 0 To len2
        
            ' instr(시작위치, 범위, 찾을 값)
            ' testArray1 자체에서 공백을 제거했더니 위치 판단이 잘못돼서
            ' testArray1(i)와 testArray2(j)가 공백이 아닐 경우에만 처리하는 것으로 변경
            If testArray1(i) <> "" And testArray2(j) <> "" Then
                
                ' testArray1(i)가 testArray2(j)에 포함되는지 또는
                ' testArray2(j)가 testArray1(i)에 포함되는지 판단
                If InStr(testArray2(j), testArray1(i)) > 0 Or _
                    InStr(testArray1(i), testArray2(j)) > 0 Then
                    
                    ' testArray1의 i번째 글자와 testArray2의 j번째 글자를 빨간색으로 칠함
                    Call font_red(testArray1, i, Range("a1"))
                    Call font_red(testArray2, j, Range("a2"))
                    
                End If
            End If
        Next
    Next
    
    ' 화면 갱신하는 것으로 복구
    Application.ScreenUpdating = True
End Sub

Function location_array_num(Array_Name, i) As Integer
    Dim c As Variant
    Dim num As Integer
    num = -1
    For Each c In Array_Name
        ' Array_Num배열의 i번째 인덱스에 해당하는 글자의 끝 위치를 구함
        location_array_num = location_array_num + Len(c) + 1
        num = num + 1
        If num = i Then
            Exit For
        End If
    Next
End Function

Sub font_red(Array_Name, num, Range_A)
        Dim a1_start_address As Integer, a1_end_address As Integer
        ' testArray1 또는 testArray2 배열의 num - 1번째 글자의 시작 위치를 구함
        If num > 0 Then
            a1_start_address = location_array_num(Array_Name, num - 1)
        Else
            a1_start_address = 1
        End If
        
        ' testArray1 또는 testArray2 배열의 num번째 글자의 끝 위치를 구함
        a1_end_address = location_array_num(Array_Name, num)
        
        ' Array_Name 배열의 i번째 글자의 색을 빨간색으로 칠함
        Range_A.Characters(Start:=a1_start_address, Length:=a1_end_address - a1_start_address).Font.Color = vbRed
End Sub


Sub font_black()
    Range("A1:A2").Font.ColorIndex = xlAutomatic
End Sub

 
 

3. 매크로 설명

 

가. 변수 선언

Dim len1 As Integer, len2 As Integer, i As Integer, j As Integer

- len1과 len2는 배열의 크기를 저장할 변수이고,
- i와 j는 for 반복문의 Counter입니다.
- 둘 다 형식을 정수로 정했습니다.
 

나. 배열 다루기

(1) 배열 선언

Dim testArray1() As String, testArray2() As String

- 변수 testArray1와 testArray1을 문자 형식으로 선언하는데, 크기는 괄호 안에 숫자를 넣어서 정하는데, 빈칸으로 둬서 정하지 않습니다.
 
(2) 배열에 값 할당

    testArray1 = Split(Range("a1"))
    testArray2 = Split(Range("a2"))

- testArray1에는 A1셀의 내용을 빈칸을 기준으로 나눈 값을 저장합니다.
- testArray2에는 A2셀의 내용을 빈칸을 기준으로 나눈 값을 저장합니다.
 
(3) 배열의 크기

    len1 = UBound(testArray1)
    len2 = UBound(testArray2)

- Ubound 함수는 배열 요소(element)의 가장 큰 인덱스를 반환하며, 배열 요소의 인덱스는 0부터 시작합니다.
 
 

다. 반복문

(1) For  ~ Next 문

    ' testArray1 배열을 하나씩 이동하면서 처리
    For i = 0 To len1
    
        ' testArray2 배열을 하나씩 이동하면서 처리
        For j = 0 To len2
            (실행문)
        Next
    Next

- For문 안에 For문이 있는 중첩 반복문입니다.
- i가 0일 때 j가 0부터 len2까지 변하고,
  i가 1일 때 j가 0부터 len2까지 변하는 것을
  i가 len1일 때까지 반복합니다.
 
(2) For Each  ~ Next 문

For Each element In group
    (실행문)
Next

- For Each c In Array_Name : 배열 내 각 요소를 하나씩 실행합니다.
 
 

라. 조건문

If testArray1(i) <> "" And testArray2(j) <> "" Then
    If InStr(testArray2(j), testArray1(i)) > 0 Or _
        InStr(testArray1(i), testArray2(j)) > 0 Then
        (실행문)
    End If
End If

- If문 안에 If문을 넣어서 첫 번째 조건이 충족될 경우에 한해서 두 번째 조건문이 실행됩니다.
- <>는 같지 않다는 의미의 비교 연산자이고, ""는 공백이라는 의미이므로 <>""는 공백이 아닐 경우가 됩니다.
 
 

마. 주요 함수

(1) Split
VBA에 없는 VB의 메서드를 VBA에서 사용할 수 있는 경우가 있습니다. Split 메서드가 그 한 예입니다.
 
구문은 아래와 같이 Expression(표현식, 범위 또는 문자열), Delimiter(구분자, 기본값이 " ", 공백 1칸), Limit(글자의 크기, 기본값은 제한 없음), Compare(비교 방법)인데,
public static string[] Split (string? Expression, string? Delimiter = " ", int Limit = -1, Microsoft.VisualBasic.CompareMethod Compare = Microsoft.VisualBasic.CompareMethod.Binary);
 
공백 한 칸으로 구분하고, 글자의 크기에 제한이 없으며, 특별히 비교 방식을 설정할 필요가 없으므로
Split(Range("a1"))이라고 문자열이 있는 셀 주소만 입력하면 공백 1칸을 기준으로 문장을 분리해 줍니다.
 
위에서는 testArray1 = Split(Range("a1"))라고 해서 공백을 기준으로 분리한 문자열을 testArray1 배열에 저장합니다.
 
(2) InStr함수
구문이 InStr([start, ] string1, string2 [, compare])로 대괄호 안에 있는 것은 옵션이므로 입력하지 않아도 됩니다.
string1은 검색 대상 문자열, string2가 검색 문자열입니다.
 
다시 말해 instr("저기에 고양이가 있다","고양이")라고 하면 5가 반환됩니다.
 

InStr(testArray2(j), testArray1(i)) 

testArray1(i)를 testArray2(j)에서 찾아서 위치를 반환해 주는 것으로 0이면 찾는 것이 없는 것이고,
0보다 크다면 찾는 문자열이 있는 것입니다. 따라서, 0보다 커야 합니다.
 

If InStr(testArray2(j), testArray1(i)) > 0 Or _
        InStr(testArray1(i), testArray2(j)) > 0 Then

- 첫 줄 끝에 있는 _는 두 번째 줄이 첫 번째 줄과 연결된다는 의미입니다. 다시 말해 원해는 한 줄로 써야 하는데, 문장이 길 경우는 _를 입력한 다음, 다음 줄에 입력해서 보기에 편리하도록 할 수 있습니다.
 
- 위 조건문은 testArray1(i)아 testArray2(j)에 있거나 그와 반대로 testArray2(j)가 testArray1(i)에 있는 경우입니다. Or 연산자를 사용했으므로 둘 중 하나만 충족하면 됩니다.
 
(3) Len함수
구문이 LEN(text)로 text는 문자열이므로 문자열 대신 셀 주소가 될 수도 있습니다.
위 경우는 배열의 요소인 문자열의 개수를 구하기 위해 Len(c)라고 사용했습니다.
 

바. 속성

(1) Range.Characters property
 
구문은 Range.Characters(시작 위치, 길이)입니다.
 
Range("a1").characters(5,3).font.color=vbred 라고 하면
A1셀의 다섯 번째부터 3글자의 색을 빨간색으로 바꿉니다.
 
직접 실행창에 Range("a1").characters(5,3).font.color=vbred 라고 입력하고 엔터 키를 누르면

다섯 번째 위치 '마'부터 세 글자인 '마음과'가 빨간색으로 변경됩니다.

 
(2) Application.ScreenUpdating Property
매크로 실행시마다 화면을 갱신할 것인지 설정하는 것으로
Application.ScreenUpdating = True 이면 화면을 매번 갱신하고,
Application.ScreenUpdating = False 이면 화면을 갱신하지 않습니다.
 
매크로를 끝낼 때는 반드시 Application.ScreenUpdating = True로 돌려놔야 합니다.
 

4. 단추(명령 버튼) 만들기

가. 문자 비교 단추 만들기

개발 도구 - 삽입 - 단추(양식 컨트롤)를 누르고,

 
버튼을 C열에서 E열 사이에 적당하게 그리면, 아래와 같이 매크로 이름을 선택하라고 하는데, 'compare_sentence를 클릭하고 확인 버튼을 누릅니다.

 
그러면 아래와 같이 단추 이름이 단추 3이라고 표시되므로 마우스 오른쪽 버튼을 누른 다음

 
텍스트 편집 메뉴를 누릅니다.

그러면 단추 3의 맨 앞에 커서가 위치하는데, 문장 비교라고 수정하고, Esc키를 누릅니다.

그러면 단추의 이름이 문장 비교로 바뀝니다.

 

나. 초기화 버튼 만들기

개발 도구 - 삽입 - 단추를 누른 다음 font_black 매크로와 연결하고, 단추의 이름을 초기화로 수정해서 초기화 버튼을 만듭니다.
 

 
버튼의 높이가 다르므로 문장 비교 버튼을 복사한 후 연결 매크로와 텍스트를 수정해도 되고,
 
아래와 같이 Shift키를 누른 상태에서 마우스 오른쪽 버튼으로 단추 두 개를 눌러 모두 선택한 후 '크기 및 속성' 메뉴를 누르고,

크기를 8 mm로 통일하고,

 
도형 서식 탭에서 맞춤 - 위쪽 맞춤을 눌러 위치를 맞출 수도 있습니다.

 

문장비교.xlsm
0.02MB


실행과 관련된 내용은 다음 편에서 다루겠습니다.

반응형