엑셀 매크로 내에서 자바스크립트를 어떻게 사용할 수 있습니까?
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 라이브러리를 사용할 수 있었다고 가정하면, 오픈 소스 Excel 추가 기능인 ExcelDna(http://www.codeplex.com/exceldna), 를 사용하여 .NET 코드 통합을 쉽게 할 수 있었을 것입니다.
제 마지막 아이디어는 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
(글로벌 obj를 하나만 유지하려고 노력했습니다.WMI 서비스와 objDiff는 각 셀에 대해 이러한 기능을 생성/제거할 필요가 없지만 성능에는 차이가 없는 것 같습니다.)
그리고 나서 저는 제 메인 매크로를 작성했습니다.원래 값의 범위(한 열), 새 값의 범위, 디프가 결과를 덤프해야 하는 범위 등 세 가지 매개 변수가 필요합니다.모두 행 수가 동일한 것으로 가정되며, 심각한 오류 검사는 진행하지 않습니다.
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 Script Components"라는 것을 통해 가능합니다.
다음은 WSC를 만드는 방법에 대한 튜토리얼입니다.
윈도우즈 스크립트 구성 요소는 스크립트에 정의된 COM 구성 요소입니다.구성 요소에 대한 인터페이스는 COM을 통해 이루어지며, 이는 VBA 친화적임을 의미합니다.이 논리는 JavaScript 또는 VBScript와 같은 Windows Script 호스팅 호환 언어로 구현됩니다.WSC는 논리, 구성 요소 클래스 ID, 메서드, 등록 논리 등이 포함된 단일 XML 파일에 정의됩니다.
WSC를 만드는 데 도움이 되는 도구도 있습니다.기본적으로 사용자에게 질문을 하고 XML 템플릿을 채우는 마법사 유형입니다.저는 샘플 .wsc 파일로 시작해서 텍스트 편집기로 손으로 편집했습니다.그것은 꽤 자기 설명적입니다.
스크립트에서 이렇게 정의된 COM 구성 요소(.wsc 파일)는 다른 COM 구성 요소와 마찬가지로 COM과 함께 춤을 출 수 있는 모든 환경에서 호출할 수 있습니다.
업데이트: 잠시 시간을 내어 Google Diff용 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>
그것을 사용하려면, 당신은 그것을 해야 합니다.탐색기에서 마우스 오른쪽 단추를 클릭하고 "등록"을 선택하거나 명령줄에서 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의 인터op 기능을 사용하여 COM 객체로 노출할 수 있도록 합니다.
또는 Windows Scripting Host 개체를 사용하여 Javascript 파일을 실행하고 결과를 반환하는 방법도 검토할 수 있습니다.
여기 고려해야 할 다른 옵션이 있습니다. 비록 제가 그것이 가장 좋은 것이라고 결코 말하지는 않지만요.
- Python 버전이 IronPython으로 컴파일되는지 확인하십시오. (여기에는 문제가 없거나 최대 소량의 포팅만 가능합니다.)
- C#을 사용하여 Excel 추가 라이브러리를 만들고 여기서 IronPython을 참조합니다.
- 필요한 기능을 C# Excel 추가 기능으로 래핑합니다.
언급URL : https://stackoverflow.com/questions/848246/how-can-i-use-javascript-within-an-excel-macro
'programing' 카테고리의 다른 글
UNION을 사용하여 여러 테이블에서 조건에 따라 테이블을 선택하시겠습니까? (0) | 2023.06.17 |
---|---|
관측 가능한 .do() 연산자(rxjs)의 사용 사례 (0) | 2023.06.17 |
엑셀 없이 델파이에서 엑셀로 내보내기 (0) | 2023.06.17 |
Excel VBA 코드의 XMLHttp 응답에서 JSON 개체 처리 (0) | 2023.06.12 |
Angular2(TypeScript)의 유닛 테스트/모킹 창 속성 (0) | 2023.06.12 |