문제

여기 Google에서 호스팅하는 정말 멋진 diff 클래스가 있습니다.

http://code.google.com/p/google-diff-match-patch/

이전에 몇몇 웹사이트에서 사용했는데 이제는 사용해야 합니다. 이내에 두 셀 사이의 텍스트를 비교하는 Excel 매크로입니다.

그러나 VBA가 아닌 JavaScript, Python, Java 및 C++에서만 사용할 수 있습니다.

내 사용자는 Excel 2003으로 제한되어 있으므로 순수 .NET 솔루션은 작동하지 않습니다.코드를 VBA로 수동으로 변환하면 시간이 너무 많이 걸리고 업그레이드가 어려워집니다.

제가 고려한 옵션 중 하나는 .NET 컴파일러(JScript.NET 또는 J#)를 사용하여 JavaScript 또는 Java 소스를 컴파일하고 Reflector를 사용하여 VB.NET으로 출력한 다음 마지막으로 VB.NET 코드를 수동으로 VBA로 다운그레이드하여 순수한 VBA 솔루션..NET 컴파일러로 컴파일하는 데 문제가 발생한 후 이 경로를 포기했습니다.

작동하는 .NET 라이브러리를 얻을 수 있었다면 ExcelDna(http://www.codeplex.com/exceldna)는 .NET 코드 통합을 더 쉽게 해주는 오픈 소스 Excel 추가 기능입니다.

마지막 아이디어는 Internet Explorer 개체를 호스팅하고 JavaScript 소스를 보내고 호출하는 것이었습니다.비록 내가 이것을 작동시키더라도, 내 생각엔 그것은 매우 느리고 지저분할 것입니다.

업데이트:해결책을 찾았습니다!

승인된 답변으로 아래 설명된 WSC 방법을 사용했습니다.차이점을 정리하고 VBA 호환 배열 배열을 돌려주기 위해 WSC 코드를 약간 변경해야 했습니다.

function DiffFast(text1, text2)
{
    var d = dmp.diff_main(text1, text2, true);
    dmp.diff_cleanupSemantic(d);
    var dictionary = new ActiveXObject("Scripting.Dictionary"); // VBA-compatible array
    for ( var i = 0; i < d.length; i++ ) {
    dictionary.add(i, JS2VBArray(d[i]));
    }
    return dictionary.Items();
}

function JS2VBArray(objJSArray)
{
    var dictionary = new ActiveXObject("Scripting.Dictionary");
    for (var i = 0; i < objJSArray.length; i++) {
        dictionary.add( i, objJSArray[ i ] );
        }
    return dictionary.Items();
}

WSC를 등록했는데 잘 작동했습니다.이를 호출하기 위한 VBA의 코드는 다음과 같습니다.

Public Function GetDiffs(ByVal s1 As String, ByVal s2 As String) As Variant()
    Dim objWMIService As Object
    Dim objDiff As Object
    Set objWMIService = GetObject("winmgmts:")
    Set objDiff = CreateObject("Google.DiffMatchPath.WSC")
    GetDiffs = objDiff.DiffFast(s1, s2)
    Set objDiff = Nothing
    Set objWMIService = Nothing
End Function

(단일 전역 objWMIService 및 objDiff를 유지하려고 했기 때문에 각 셀에 대해 이를 생성/파괴할 필요가 없었지만 성능에는 차이가 없는 것 같습니다.)

그런 다음 주요 매크로를 작성했습니다.세 가지 매개변수가 필요합니다.원래 값의 범위(1개 열), 새 값의 범위 및 diff가 결과를 덤프해야 하는 범위입니다.모두는 추정 동일한 수의 행을 갖기 위해 여기서는 심각한 오류 검사가 진행되지 않습니다.

Public Sub DiffAndFormat(ByRef OriginalRange As Range, ByRef NewRange As Range, ByRef DeltaRange As Range)
    Dim idiff As Long
    Dim thisDiff() As Variant
    Dim diffop As String
    Dim difftext As String
    difftext = ""
    Dim diffs() As Variant
    Dim OriginalValue As String
    Dim NewValue As String
    Dim DeltaCell As Range
    Dim row As Integer
    Dim CalcMode As Integer

다음 세 줄은 나중에 사용자가 선호하는 계산 모드를 방해하지 않고 업데이트 속도를 높입니다.

    Application.ScreenUpdating = False
    CalcMode = Application.Calculation
    Application.Calculation = xlCalculationManual
    For row = 1 To OriginalRange.Rows.Count
        difftext = ""
        OriginalValue = OriginalRange.Cells(row, 1).Value
        NewValue = NewRange.Cells(row, 1).Value
        Set DeltaCell = DeltaRange.Cells(row, 1)
        If OriginalValue = "" And NewValue = "" Then

이전 차이점이 있는 경우 삭제하는 것이 중요합니다.

            Erase diffs

이 테스트는 사용자를 위한 시각적 지름길이므로 전혀 변경 사항이 없을 때 명확하게 알 수 있습니다.

        ElseIf OriginalValue = NewValue Then
            difftext = "No change."
            Erase diffs
        Else

텍스트가 동일하거나 삽입되었거나 삭제되었는지 여부에 관계없이 모든 텍스트를 델타 셀 값으로 결합합니다.

            diffs = GetDiffs(OriginalValue, NewValue)
            For idiff = 0 To UBound(diffs)
                thisDiff = diffs(idiff)
                difftext = difftext & thisDiff(1)
            Next
        End If

값을 설정해야 합니다. ~ 전에 포맷 시작하기:

        DeltaCell.value2 = difftext
        Call FormatDiff(diffs, DeltaCell)
    Next
    Application.ScreenUpdating = True
    Application.Calculation = CalcMode
End Sub

차이점을 해석하고 델타 셀의 형식을 지정하는 코드는 다음과 같습니다.

Public Sub FormatDiff(ByRef diffs() As Variant, ByVal cell As Range)
    Dim idiff As Long
    Dim thisDiff() As Variant
    Dim diffop As String
    Dim difftext As String
    cell.Font.Strikethrough = False
    cell.Font.ColorIndex = 0
    cell.Font.Bold = False
    If Not diffs Then Exit Sub
    Dim lastlen As Long
    Dim thislen As Long
    lastlen = 1
    For idiff = 0 To UBound(diffs)
        thisDiff = diffs(idiff)
        diffop = thisDiff(0)
        thislen = Len(thisDiff(1))
        Select Case diffop
            Case -1
                cell.Characters(lastlen, thislen).Font.Strikethrough = True
                cell.Characters(lastlen, thislen).Font.ColorIndex = 16 ' Dark Gray http://www.microsoft.com/technet/scriptcenter/resources/officetips/mar05/tips0329.mspx
            Case 1
                cell.Characters(lastlen, thislen).Font.Bold = True
                cell.Characters(lastlen, thislen).Font.ColorIndex = 32 ' Blue
        End Select
        lastlen = lastlen + thislen
    Next
End Sub

최적화할 수 있는 기회가 몇 가지 있지만 지금까지는 잘 작동하고 있습니다.도움을 주신 모든 분들께 감사드립니다!

도움이 되었습니까?

해결책

가장 간단한 접근 방식은 Javascript를 사용하여 Javascript diff 논리를 COM 구성 요소에 직접 포함시키는 것입니다.이는 "Windows 스크립트 구성 요소".

여기 WSC 생성에 대한 튜토리얼.

Windows 스크립트 구성 요소는 스크립트에 정의된 COM 구성 요소입니다.구성 요소에 대한 인터페이스는 COM을 통해 이루어지며 이는 VBA 친화적임을 의미합니다.논리는 JavaScript 또는 VBScript와 같은 Windows 스크립팅 호스팅 호환 언어로 구현됩니다.WSC는 논리, 구성 요소 클래스 ID, 메서드, 등록 논리 등이 포함된 단일 XML 파일로 정의됩니다.

또한 WSC 생성에 도움이 되는 도구.기본적으로 이는 질문을 하고 XML 템플릿을 채우는 마법사 형식의 작업입니다.저는 방금 예제 .wsc 파일로 시작하여 텍스트 편집기를 사용하여 직접 편집했습니다.그것은 꽤 자명하다.

스크립트(.wsc 파일)에서 이러한 방식으로 정의된 COM 구성 요소는 COM과 함께 작동할 수 있는 모든 환경에서 다른 COM 구성 요소와 마찬가지로 호출 가능합니다.

업데이트:나는 몇 분 정도 시간을 들여 GoogleDiff용 WSC를 제작했습니다.여기있어.

<?xml version="1.0"?>

<package>

<component id="Cheeso.Google.DiffMatchPatch">

  <comment>
    COM Wrapper on the Diff/Match/Patch logic published by Google at http://code.google.com/p/google-diff-match-patch/.
  </comment>

<?component error="true" debug="true"?>

<registration
  description="WSC Component for Google Diff/Match/Patch"
  progid="Cheeso.Google.DiffMatchPatch"
  version="1.00"
  classid="{36e400d0-32f7-4778-a521-2a5e1dd7d11c}"
  remotable="False">

  <script language="VBScript">
  <![CDATA[

    strComponent = "Cheeso's COM wrapper for Google Diff/Match/Patch"

    Function Register
      MsgBox strComponent & " - registered."
    End Function

    Function Unregister
      MsgBox strComponent & " - unregistered."
    End Function

  ]]>
  </script>
</registration>


<public>
  <method name="Diff">
    <parameter name="text1"/>
    <parameter name="text2"/>
  </method>
  <method name="DiffFast">
    <parameter name="text1"/>
    <parameter name="text2"/>
  </method>
</public>


<script language="Javascript">
<![CDATA[


    // insert original google diff code here...


// public methods on the component
var dpm = new diff_match_patch();


function Diff(text1, text2)
{
   return dpm.diff_main(text1, text2, false);
}


function DiffFast(text1, text2)
{
   return dpm.diff_main(text1, text2, true);
}


]]>
</script>

</component>

</package>

그 것을 사용하려면 등록을 해야 합니다.Explorer에서 마우스 오른쪽 버튼을 클릭하고 "등록"을 선택하십시오.또는 명령줄에서 다음을 수행합니다.regsvr32 파일:\c:\scripts\GoogleDiff.wsc

VBA에서는 사용해 보지 않았지만 여기에 해당 구성 요소를 사용하는 일부 VBScript 코드가 있습니다.

Sub TestDiff()
    dim t1 
    t1 = "The quick brown fox jumped over the lazy dog."

    dim t2 
    t2 = "The large fat elephant jumped over the cowering flea."

    WScript.echo("")

    WScript.echo("Instantiating a Diff Component ...")
    dim d
    set d = WScript.CreateObject("Cheeso.Google.DiffMatchPatch")

    WScript.echo("Doing the Diff...")
    x = d.Diff(t1, t2)

    WScript.echo("")
    WScript.echo("Result was of type: " & TypeName(x))
    ' result is all the diffs, joined by commas.  
    ' Each diff is an integer (position), and a string.  These are separated by commas.
    WScript.echo("Result : " & x)

    WScript.echo("Transform result...")
    z= Split(x, ",")
    WScript.echo("")
    redim diffs(ubound(z)/2)
    i = 0
    j = 0
    For Each item in z
      If (j = 0) then
        diffs(i) = item
        j = j+ 1      
      Else 
          diffs(i) = diffs(i) & "," & item
        i = i + 1
        j = 0
      End If
    Next

    WScript.echo("Results:")
    For Each item in diffs
      WScript.echo("  " & item)
    Next

    WScript.echo("Done.")

End Sub

다른 팁

그만큼 Windows 스크립팅 엔진 JavaScript 라이브러리를 실행할 수 있습니다.내 경험으로는 잘 작동합니다.

내 제안은 무엇을 하든 COM 래퍼로 포장하는 것입니다.VBA는 COM 개체를 가장 잘 처리하므로 .NET 구성 요소로 컴파일한 다음 .NET의 상호 운용성 기능을 사용하여 COM 개체로 노출할 수 있습니다.

대안으로 Windows 스크립팅 호스트 개체를 사용하여 Javascript 파일을 실행하고 결과를 반환할 수도 있습니다.

고려해야 할 또 다른 옵션이 있지만 그것이 최선이라고 말할 수는 없습니다.

  • Python 버전이 IronPython에서 컴파일되는지 확인하세요.(여기에는 문제가 없거나 기껏해야 약간의 포팅만 있으면 됩니다.)
  • C#을 사용하여 Excel 추가 기능 라이브러리를 만들고 여기에서 IronPython을 참조합니다.
  • C# Excel 추가 기능에 필요한 기능을 래핑합니다.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top