네이버 국어사전/영어사전 검색 도구 동작 방식과 소스코드

네이버 국어사전/영어사전 검색 도구 동작 방식과 소스코드 에 대해 설명한다.

이전 글에서 이어지는 내용이다.

네이버 국어사전/영어사전 검색 도구 개요

1. 네이버 국어사전/영어사전 검색 도구 동작 방식과 주의사항

사용자가 웹브라우저를 이용하여 검색어를 네이버 서비스에 검색을 요청(Request)하고, 네이버 서버는 요청에 대한 처리결과를 응답(Response)한다.

(Web 동작 방식에 대한 자세한 내용은 아래 구글 검색결과의 글을 읽어보기 바란다.)
https://www.google.co.kr/search?q=web+동작+방식

네이버 사전 서비스의 검색 요청(Request)과 응답(Response)에 대해 자세히 살펴보자.

1.1. 네이버 사전 검색 요청과 응답

웹 브라우저를 통해 서버와 주고 받는 내용을 확인하는 방법은 여러 가지가 있는데, 여기에서는 Fiddler Web Debugger로 설명하겠다.

아래는 네이버 국어사전에서 “가입” 이라는 단어를 검색했을 때 요청과 응답내용을 Fiddler에서 확인한 결과이다.

Fiddler로 살펴본 네이버 사전 검색 요청과 응답
Fiddler로 살펴본 네이버 사전 검색 요청과 응답
  1. URL, Content-Type: 아래 내용을 확인할 수 있다.
    • Protocol: HTTPS
    • Host: ko.dict.naver.com
    • URL: /api3/koko/search?query=%EA%B0%80%EC%9E%85&m=pc&hid=162470754628591300
      • 여기에서 “%EA%B0%80%EC%9E%85″는 “가입”이 URL Encoding된 문자열이다.
  2. 요청(Request) Header
    • User-Agent, Cookie 등의 내용을 확인할 수 있다.
  3. 응답(Response) 내용
    • Content-Type: application/json;charset=UTF-8
      • Response 내용이 json 형식이고, character-set은 UTF-8로 encoding되어 있음을 알 수 있다.
    • Content-Length: 50814
      • Response 내용이 50,814 Byte, 약 50KB 임을 알 수 있다.
    • Content-Body: {“searchResultMap”:{“searchResultListMap”:{“WORD”:{“query”:”가입”, …
      • JSON string이고, “JSON” 탭에서 확인하면 다음과 같이 계층적 구조를 가지고 있다.
네이버 국어사전 HTTP Response JSON 구조
네이버 국어사전 HTTP Response JSON 구조

1.2. 응답결과 형식 변경 (HTML –> JSON)

이 도구는 네이버 Open API를 사용하지 않고 Web Request, Response 방식을 이용한다.

정확하지는 않으나, 2018년 12월을 전후로 응답결과의 형식이 변경되었다. 그 이전에는 HTML 형식이었는데, 이 시기에 우연히 Fiddler로 확인해 보니 JSON 형식으로 응답이 변경되었음을 알게 되었다.

이 도구의 첫 버전은 응답이 HTML 형식일 때 만들어졌다. HTML에서 필요한 항목을 추출하였는데, 네이버가 HTML의 구조를 변경할 때마다 제대로 동작하지 않아 변경된 HTML구조에 맞춰서 매번 소스코드를 변경해 줘야 했었다. 응답결과 형식이 JSON으로 변경된 이후로는 소스코드 변경없이 잘 동작하고 있다.

1.3. 사용상 주의사항

네이버가 사전 검색결과를 JSON 형식으로 제공한다고 공식적으로 알렸는지 확인할 수 없다. JSON의 구조에 대한 문서도 공개되어 있지 않은 것으로 보인다.
(만약, 공개된 뉴스나 자료가 있다면 댓글로 알려주기 바란다.)

이런 이유로 어느 날 갑자기 동작하지 않을 수 있으니 주의하기 바란다.

2. 구현

2.1. 전체 흐름 요약

검색할 단어를 URL Encoding하고 GetDataFromURL 함수를 실행하여 가져온 JSON 검색결과를 parsing하여 필요한 항목을 추출한다.

Dim aWord As String, sBaseURL As String, sWord As String
aWord = "가입"
sBaseURL = "https://ko.dict.naver.com/api3/koko/search?query=%s" '기본 URL
sWord = URLEncodeUTF8(aWord) '검색어 URL Encoding

Dim sURL As String, sURLData As String, oParsedDic As Dictionary
sURL = Replace(sBaseURL, "%s", sWord) '기본 URL에 검색어 대입
sURLData = GetDataFromURL(sURL, "GET", "", "utf-8") 'URL에서 결과 가져오기
Set oParsedDic = JsonConverter.ParseJson(sURLData) 'JSON결과를 Dictionary로 변환

'JSON이 변환된 Dictionary에서 검색결과에 해당하는 항목 추출
'시작 Path: oParsedDic("searchResultMap")("searchResultListMap")("WORD")("items")

주요 함수에 대해 살펴보자.

2.2. URL Encoding하기 (URLEncodeUTF8 소스코드)

검색 요청할 URL을 URLEncoding한 문자열로 반환한다. ADODB.Stream 클래스를 사용하였다.

Public Function URLEncodeUTF8( _
   StringVal As String, _
   Optional SpaceAsPlus As Boolean = False _
) As String
  Dim bytes() As Byte, b As Byte, i As Integer, space As String

  If SpaceAsPlus Then space = "+" Else space = "%20"

  If Len(StringVal) > 0 Then
    With New ADODB.Stream
      .Mode = adModeReadWrite
      .Type = adTypeText
      .CharSet = "UTF-8"
      .Open
      .WriteText StringVal
      .Position = 0
      .Type = adTypeBinary
      .Position = 3 ' skip BOM
      bytes = .Read
    End With

    ReDim Result(UBound(bytes)) As String

    For i = UBound(bytes) To 0 Step -1
      b = bytes(i)
      Select Case b
        Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
          Result(i) = Chr(b)
        Case 32
          Result(i) = space
        Case 0 To 15
          Result(i) = "%0" & Hex(b)
        Case Else
          Result(i) = "%" & Hex(b)
      End Select
    Next i

    URLEncodeUTF8 = Join(Result, "")
  End If
End Function

ADODB 라이브러리를 사용하기 위해서 “Microsoft ActiveX Data Object 6.1 Library”를 참조 추가해야 한다. 엑셀 화면에서 Alt + F11 키를 누르고 VBA Editor로 전환하여 추가해 주면 된다.

엑셀 VBA 라이브러리 참조 추가
엑셀 VBA 라이브러리 참조 추가


2.3. Request & Get Response (GetDataFromURL 함수 소스코드)

“WinHttp.WinHttpRequest” 클래스를 이용하여 Request header, option 정보를 설정하고, 검색 URL을 방문하여 결과를 얻어온다. CreateObject로 개체를 생성하는 late binding 방식이라 라이브러리 참조 추가할 필요는 없다.

Function GetDataFromURL(strURL, strMethod, strPostData, Optional strCharSet = "UTF-8")
  Dim lngTimeout
  Dim strUserAgentString
  Dim intSslErrorIgnoreFlags
  Dim blnEnableRedirects
  Dim blnEnableHttpsToHttpRedirects
  Dim strHostOverride
  Dim strLogin
  Dim strPassword
  Dim strResponseText
  Dim objWinHttp
  lngTimeout = 59000
  strUserAgentString = "http_requester/0.1"
  intSslErrorIgnoreFlags = 13056 ' 13056: ignore all err, 0: accept no err
  blnEnableRedirects = True
  blnEnableHttpsToHttpRedirects = True
  strHostOverride = ""
  strLogin = ""
  strPassword = ""
  Set objWinHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
  '--------------------------------------------------------------------
  'objWinHttp.SetProxy 2, "xxx.xxx.xxx.xxx:xxxx", "" 'Proxy를 사용하는 환경에서 설정
  '--------------------------------------------------------------------
  objWinHttp.SetTimeouts lngTimeout, lngTimeout, lngTimeout, lngTimeout
  objWinHttp.Open strMethod, strURL
  If strMethod = "POST" Then
    objWinHttp.SetRequestHeader "Content-type", "application/x-www-form-urlencoded; charset=UTF-8"
  Else
    objWinHttp.SetRequestHeader "Content-type", "text/html; charset=euc-kr"
  End If
  If strHostOverride <> "" Then
    objWinHttp.SetRequestHeader "Host", strHostOverride
  End If

  objWinHttp.Option(0) = strUserAgentString
  objWinHttp.Option(4) = intSslErrorIgnoreFlags
  objWinHttp.Option(6) = blnEnableRedirects
  objWinHttp.Option(12) = blnEnableHttpsToHttpRedirects
  If (strLogin <> "") And (strPassword <> "") Then
    objWinHttp.SetCredentials strLogin, strPassword, 0
  End If
  On Error Resume Next
  objWinHttp.Send (strPostData)
  objWinHttp.WaitForResponse
  If Err.Number = 0 Then
    If objWinHttp.Status = "200" Then
      'GetDataFromURL = objWinHttp.ResponseText
      GetDataFromURL = BinaryToText(objWinHttp.ResponseBody, strCharSet)
    Else
      GetDataFromURL = "HTTP " & objWinHttp.Status & " " & _
        objWinHttp.StatusText
    End If
  Else
    GetDataFromURL = "Error " & Err.Number & " " & Err.Source & " " & _
      Err.Description
  End If
  On Error GoTo 0
  Set objWinHttp = Nothing
End Function

2.4. Response(검색결과) JSON 문자열

Response(검색결과) JSON 문자열은 상당히 많은 정보를 포함하고 있다. 들여쓰기와 행구분이 없어 보기가 어려운데, 보기 좋게 정리하면 아래와 같다. (일부만 발췌함)

{
  "searchResultMap": {
    "searchResultListMap": {
      "WORD": {
        "query": "가입",
        "queryRevert": "",
        "items": [
          {
            "rank": "1",
            "gdid": "8800000f_4002c436c93d4bb38d3e58632fe00af0",
            "matchType": "exact:entry",
            "entryId": "4002c436c93d4bb38d3e58632fe00af0",
            "serviceCode": "1",
            "languageCode": "KOKO",
            "expDictTypeForm": "단어",
            "dictTypeForm": "2",
            "sourceDictnameKO": "표준국어대사전",
            "sourceDictnameOri": "Standard Korean Dict.",
            "sourceDictnameLink": "https://stdict.korean.go.kr/main/main.do",
            ...
            "expEntry": "<strong>가입</strong>",
            ...
            "destinationLink": "#/entry/koko/4002c436c93d4bb38d3e58632fe00af0",
            ...
            "meansCollector": [
              {
                "partOfSpeech": "명사",
                "partOfSpeech2": "noun",
                "means": [
                  {
                    "order": "1",
                    "value": "조직이나 단체 따위에 들어가거나, 서비스를 제공하는 상품 따위를 신청함.",
                    ...
                    "exampleOri": "<strong>가입</strong> 신청서.",
                    ...
                  },
                  {
                    "order": "2",
                    "value": "새로 더 집어넣음.",
                    ...
                    "exampleOri": "원고 중간에 수정된 내용의 <strong>가입</strong>이 발견되었다.",
                    ...
                  },
                  {
                    "order": "3",
                    "value": "조약문의 인증 절차 없이, 그 조약에 드는 행위. 의사 표시만으로 당사자가 될 수 있게 하여 법 공동체...",
                    ...
                    "languageGroup": "법률",
                    ...
                    "exampleTrans": null,
                    ...
                  }
                ]
              }
            ],
            "similarWordList": [],
            "antonymWordList": [
              {
                "antonymWordName": "탈퇴",
                "antonymWordLink": "#/entry/koko/14e89175152b46569c2a2b6360e835ad"
              }
            ],
            "expAliasEntryAlwaysList": [],
            "expAliasGeneralAlwaysList": [
              {
                "originLanguageValue": "加入"
              }
            ],
            ...
          },
          {
            "rank": "2",
            "gdid": "881857e6_e12c4e3432cf458c929bd49c929fd80b",
            "matchType": "exact:entry",
            "entryId": "e12c4e3432cf458c929bd49c929fd80b",
            "serviceCode": "1",
            "languageCode": "KOKO",
            "expDictTypeForm": "단어",
            "dictTypeForm": "2",
            "sourceDictnameKO": "우리말샘",
            "sourceDictnameOri": "Urimalsaem",
            "sourceDictnameLink": "https://opendict.korean.go.kr/main",
            ...
            "expEntry": "<strong>가입</strong>",
            ...
            "destinationLink": "#/entry/koko/e12c4e3432cf458c929bd49c929fd80b",
            ...
            "meansCollector": [
              {
                "partOfSpeech": "명사",
                "partOfSpeech2": "noun",
                "means": [
                  {
                    "order": "",
                    "value": "어떤 개체군에 새로운 개체가 더해지는 것. 단, 일정한 발육 단계에 도달한 개체만 해당된다.",
                    ...
                  }
                ]
              }
            ],
            "similarWordList": [],
            "antonymWordList": [],
            ...
          },
        ],
        "total": 96,
        "sectionType": "WORD",
        "revert": "",
        "orKEquery": null
      }
    }
  }
}


2.5. JSON parser

문자열 함수(MID, INSTR 등)를 사용하여 JSON 문자열에서 원하는 항목을 추출해 낼 수는 있으나, 탐색이 복잡하고 코드가 매우 지저분해 진다.

Python으로 구현하면 간단히 json module을 import하고, json 클래스를 사용하면 된다. VBA는 공개된 라이브러리가 많지 않은데, 다행히 github에 공개된 JSON parser가 있어서 잘 사용하였다.

https://github.com/VBA-tools/VBA-JSON

이 JSON parser의 소스코드는 1,123 행이나 되어 블로그에 올려놓지는 않는다. 필요한 분들은 위 URL에서 소스코드를 확인하기 바란다. JSON parser를 사용하는 간단한 예시는 다음과 같다.(위 github에 공개된 코드)

Dim Json As Object
Set Json = JsonConverter.ParseJson("{""a"":123,""b"":[1,2,3,4],""c"":{""d"":456}}")

' Json("a") -> 123
' Json("b")(2) -> 2
' Json("c")("d") -> 456
Json("c")("e") = 789

Debug.Print JsonConverter.ConvertToJson(Json)
' -> "{"a":123,"b":[1,2,3,4],"c":{"d":456,"e":789}}"

Debug.Print JsonConverter.ConvertToJson(Json, Whitespace:=2)
' -> "{
'       "a": 123,
'       "b": [
'         1,
'         2,
'         3,
'         4
'       ],
'       "c": {
'         "d": 456,
'         "e": 789  
'       }
'     }"

2.6. 검색 버튼 클릭 이벤트 소스코드

“사전검색” 시트에서 “네이버 사전 검색” 버튼을 클릭했을 때 실행되는 코드이다. 다음 내용이 구현되어 있다.

  • 옵션 설정이 잘 되어 있는지 확인한다.
  • 검색어에 대해 사전 검색을 반복 실행하여 결과를 시트에 표시한다.
    • 표시되는 결과는 matchType, searchEntry, meaning, link, 유의어, 반의어이다.
  • 실행중 “검색 중지” 버튼이 눌렸다면 반복을 멈춘다.
Private Sub cmdRunDicSearch_Click()
    Range("A1").Select
    DoEvents
    
    Dim bIsKorDicSearch As Boolean, bIsEngDicSearch As Boolean, sTargetDic As String
    bIsKorDicSearch = chkKorDic.Value: bIsEngDicSearch = chkEngDic.Value
    If (Not bIsKorDicSearch) And (Not bIsEngDicSearch) Then
        MsgBox "검색 대상 사전중 적어도 1개는 선택해야 합니다", vbExclamation + vbOKOnly, "검색 대상 사전 확인"
        Exit Sub
    End If

    Dim bIsMatchTypeExact As Boolean, bIsMatchTypeTermOr As Boolean, bIsMatchTypeAllTerm As Boolean '검색결과 표시 설정
    bIsMatchTypeExact = chkMatchTypeExact.Value: bIsMatchTypeTermOr = chkMatchTypeTermOr.Value: bIsMatchTypeAllTerm = chkMatchTypeAllTerm.Value

    If (bIsMatchTypeExact Or bIsMatchTypeTermOr Or bIsMatchTypeAllTerm) = False Then
        MsgBox "검색결과 표시 설정중 적어도 하나는 선택해야 합니다.", vbExclamation + vbOKOnly, "확인"
        Exit Sub
    End If

    If bIsKorDicSearch And Not bIsEngDicSearch Then sTargetDic = "국어사전"
    If Not bIsKorDicSearch And bIsEngDicSearch Then sTargetDic = "영어사전"
    If bIsKorDicSearch And bIsEngDicSearch Then sTargetDic = "국어사전, 영어사전"
    
    Dim lMaxResultCount As Long
    lMaxResultCount = CInt(txtMaxResultCount.Value)

    If MsgBox("사전 검색을 시작하시겠습니까?" + vbLf + _
              "대상 사전: " + sTargetDic + vbLf + _
              "결과출력 제한개수: " + CStr(lMaxResultCount) _
              , vbQuestion + vbYesNoCancel, "확인") <> vbYes Then Exit Sub

    Dim i As Long, iResultOffset As Long
    bIsWantToStop = False
    DoEvents

    Dim sWord As String, oKorDicSearchResult As TDicSearchResult, oEngDicSearchResult As TDicSearchResult
    Dim oBaseRange As Range
    Set oBaseRange = Range("검색결과Header").Offset(1, 0)
    oBaseRange.Select
    For i = 0 To 100000
        If bIsWantToStop Then
            MsgBox "사용자의 요청으로 검색을 중단합니다.", vbInformation + vbOKOnly, "확인"
            Exit For
        End If
        If chkSkipIfResultExists.Value = True And _
           oBaseRange.Offset(i, 1) <> "" Then GoTo Continue_For '이미 내용이 있으면 Skip
        sWord = oBaseRange.Offset(i)
        If sWord = "" Then Exit For
        oBaseRange.Offset(i).Select

        Application.ScreenUpdating = False
        If bIsKorDicSearch Then '국어사전 검색결과 표시
            oKorDicSearchResult = DoDicSearch(dtsKorean, sWord, bIsMatchTypeExact, bIsMatchTypeTermOr, bIsMatchTypeAllTerm, lMaxResultCount)
            oBaseRange.Offset(i, 1).Select
            With oKorDicSearchResult
                oBaseRange.Offset(i, 1) = .sMatchType
                oBaseRange.Offset(i, 2) = .sSearchEntry
                oBaseRange.Offset(i, 3) = .sMeaning
                If oKorDicSearchResult.sLinkURL <> "" Then
                    With ActiveSheet.Hyperlinks.Add(Anchor:=oBaseRange.Offset(i, 4), Address:=.sLinkURL, TextToDisplay:="네이버국어사전 열기: " & .sLinkWord)
                        .Range.Font.Size = 8
                    End With
                End If
                oBaseRange.Offset(i, 5) = .sSynonymList
                oBaseRange.Offset(i, 6) = .sAntonymList
            
            End With
        End If

        If bIsEngDicSearch Then '영어사전 검색결과 표시
            oEngDicSearchResult = DoDicSearch(dtsEnglish, sWord, bIsMatchTypeExact, bIsMatchTypeTermOr, bIsMatchTypeAllTerm, lMaxResultCount)
            'oBaseRange.Offset(i, 7).Select
            With oEngDicSearchResult
                oBaseRange.Offset(i, 7) = .sMatchType
                oBaseRange.Offset(i, 8) = .sSearchEntry
                oBaseRange.Offset(i, 9) = .sMeaning
                If oKorDicSearchResult.sLinkURL <> "" Then
                    With ActiveSheet.Hyperlinks.Add(Anchor:=oBaseRange.Offset(i, 10), Address:=.sLinkURL, TextToDisplay:="네이버영어사전 열기: " & .sLinkWord)
                        .Range.Font.Size = 8
                    End With
                End If
                oBaseRange.Offset(i, 11) = .sSynonymList
                oBaseRange.Offset(i, 12) = .sAntonymList
            
            End With
        End If
        Application.ScreenUpdating = True

Continue_For:
        DoEvents
    Next i

    MsgBox "사전 검색을 완료하였습니다", vbOKOnly + vbInformation
End Sub

2.7. 사전 검색 (DoDicSearch 소스코드)

검색어 한개에 대해 검색요청을 보내고 결과를 받은 다음 필요한 항목을 추출하여 반환하는 함수이다.

  • JSON 문자열을 Dictionary로 parsing: 49행
  • matchType, searchEntry, meaning, link, 유의어, 반의어 항목 추출: 53 ~ 106행
Const DICT_ROOT_URL_KO As String = "https://ko.dict.naver.com/"
Const DICT_BASE_URL_KO As String = "https://ko.dict.naver.com/api3/koko/search?query=%s"
Const DICT_ROOT_URL_EN As String = "https://en.dict.naver.com/"
Const DICT_BASE_URL_EN As String = "https://en.dict.naver.com/api3/enko/search?query=%s"

Public Enum DicToSearch
    dtsKorean = 1
    dtsEnglish = 2
    dtsAll = 10
End Enum

Public Type TDicSearchResult
    sWord As String
    sMatchType As String
    sSearchEntry As String
    sMeaning As String
    sLinkURL As String
    sLinkWord As String
    sSynonymList As String
    sAntonymList As String
End Type

Public Function DoDicSearch(aDicToSearch As DicToSearch, aWord As String, _
    bIsMatchTypeExact As Boolean, bIsMatchTypeTermOr As Boolean, bIsMatchTypeAllTerm As Boolean, _
    aMaxResultCount As Long) As TDicSearchResult

    Dim sDicRootURL As String, sBaseURL As String, sURL As String, sURLData As String, sWord As String, oDicSearchResult As TDicSearchResult

    Dim oParsedDic As Dictionary
    Dim oItem As Dictionary, oMeansCollector As Dictionary, oMeans As Dictionary
    Dim oSimWords As Dictionary, oAntWord As Dictionary
    Dim sPOS As String, sMeaning As String, sLinkURL As String, sLinkWord As String
    Dim s유의어 As String, s유의어목록 As String, s반의어 As String, s반의어목록 As String
    Dim sMatchType As String, sSearchEntry As String, sHandleEntry As String

    Select Case aDicToSearch
        Case dtsKorean
            sDicRootURL = DICT_ROOT_URL_KO
            sBaseURL = DICT_BASE_URL_KO
        Case dtsEnglish
            sDicRootURL = DICT_ROOT_URL_EN
            sBaseURL = DICT_BASE_URL_EN
    End Select

    If aWord = "" Then Exit Function
    sWord = URLEncodeUTF8(aWord)
    sURL = Replace(sBaseURL, "%s", sWord)
    sURLData = GetDataFromURL(sURL, "GET", "", "utf-8") 'URL에서 결과 가져오기
    Set oParsedDic = JsonConverter.ParseJson(sURLData) 'JSON결과를 Dictionary로 변환

    Dim lMatchIdx As Long: lMatchIdx = 0
    Dim lResultCount As Long: lResultCount = 0
    For Each oItem In oParsedDic("searchResultMap")("searchResultListMap")("WORD")("items")
        lResultCount = lResultCount + 1
        If (aMaxResultCount <> 0) And (lResultCount > aMaxResultCount) Then Exit For '결과출력 제한개수 초과시 Loop 종료
        s유의어 = "": s반의어 = ""
        lMatchIdx = lMatchIdx + 1
        'If oItem("matchType") <> "exact:entry" Then Exit For

        sHandleEntry = oItem("handleEntry")
        Select Case oItem("matchType")
            Case "exact:entry"
                sLinkWord = sHandleEntry
                sLinkURL = sDicRootURL + oItem("destinationLink")
                If Not bIsMatchTypeExact Then GoTo Continue_InnerFor
            Case "term:or"
                If Not bIsMatchTypeTermOr Then GoTo Continue_InnerFor
            Case "allterm:proximity:1.000000"
                If Not bIsMatchTypeAllTerm Then GoTo Continue_InnerFor
            Case Else
                
        End Select

        sMatchType = sMatchType + IIf(sMatchType = "", "", vbLf) & CStr(lMatchIdx) & ". " & oItem("matchType")
        sSearchEntry = sSearchEntry + IIf(sSearchEntry = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry

        For Each oMeansCollector In oItem("meansCollector")
            'Debug.Print "품사: " & oMeansCollector("partOfSpeech")
            sPOS = ""
            If oMeansCollector.Exists("partOfSpeech") Then
                If Not IsNull(oMeansCollector("partOfSpeech")) Then sPOS = oMeansCollector("partOfSpeech")
            End If
            For Each oMeans In oMeansCollector("means")
                'Debug.Print "뜻: " & oMeans("value")
                If oMeans.Exists("value") Then
                    If Not IsNull(oMeans("value")) Then _
                        sMeaning = sMeaning + IIf(sMeaning = "", "", vbLf) & CStr(lMatchIdx) & ". " & IIf(sPOS = "", "", "[" & sPOS & "] ") & RemoveHTML(oMeans("value"))
                End If
            Next oMeans
        Next oMeansCollector
        For Each oSimWords In oItem("similarWordList")
            If oSimWords.Exists("similarWordName") Then _
                s유의어 = s유의어 + IIf(s유의어 = "", "", ", ") & RemoveHTML(oSimWords("similarWordName"))
        Next oSimWords
        If s유의어 <> "" Then _
            s유의어목록 = s유의어목록 & IIf(s유의어목록 = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry & ": " & s유의어

        For Each oAntWord In oItem("antonymWordList")
            If oAntWord.Exists("antonymWordName") Then _
                s반의어 = s반의어 + IIf(s반의어 = "", "", ", ") & RemoveHTML(oAntWord("antonymWordName"))
        Next oAntWord
        If s반의어 <> "" Then _
            s반의어목록 = s반의어목록 & IIf(s반의어목록 = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry & ": " & s반의어

Continue_InnerFor:
    Next oItem

    If sMeaning = "" Then
        sMeaning = "#NOT FOUND#": sMatchType = sMeaning: sSearchEntry = sMeaning
    End If

    '결과값 반환
    With oDicSearchResult
        .sWord = aWord
        .sMatchType = sMatchType
        .sSearchEntry = sSearchEntry
        .sMeaning = sMeaning
        .sLinkWord = sLinkWord
        .sLinkURL = Replace(sLinkURL, "#", "%23") 'Excel에서 #기호를 내부적으로 #20 - #20 으로 치환하는 것을 방지
        .sSynonymList = s유의어목록
        .sAntonymList = s반의어목록
    End With
    DoDicSearch = oDicSearchResult
End Function

이상으로 이 도구의 동작방식, 주의사항, 소스코드에 대해 살펴보았다. 도구를 사용해 보신 분들의 후기나, 궁금한 점, 필요한 기능 등 의견은 댓글로 남겨주기 바란다.


<< 관련 글 목록 >>

2 Responses

  1. 아바타 사진 Neculiti Ivan 댓글:

    Absolutely with you it agree. It is excellent idea. I support you.

    _ _ _ _ _ _ _ _ _ _ _ _ _ _
    Nekultsy Ivan dxvk github

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

ko_KR한국어