utilizar que puede para llamar insertar ejemplos desde cómo codigo caracteristicas .net javascript excel vba j#

.net - llamar - para que se puede utilizar javascript



¿Cómo puedo usar JavaScript dentro de una macro de Excel? (4)

Aquí hay otra opción para considerar, aunque de ninguna manera afirmo que es la mejor.

  • Asegúrate de que la versión de Python compila en IronPython. (No debería haber ningún problema aquí, o solo una pequeña cantidad de portabilidad como máximo).
  • Cree una biblioteca de complementos de Excel utilizando C # y haga referencia a IronPython desde allí.
  • Envuelva la funcionalidad necesaria en su complemento C # Excel.

Hay una muy buena clase de diferencias alojada por Google aquí:

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

Lo he usado anteriormente en algunos sitios web, pero ahora necesito usarlo dentro de una macro de Excel para comparar texto entre dos celdas.

Sin embargo, solo está disponible en JavaScript, Python, Java y C ++, no en VBA.

Mis usuarios están limitados a Excel 2003, por lo que una solución .NET pura no funcionaría. Traducir el código a VBA manualmente tomaría demasiado tiempo y dificultaría la actualización.

Una opción que consideré fue compilar el código fuente JavaScript o Java usando los compiladores .NET (JScript.NET o J #), usar Reflector para dar salida como VB.NET, y finalmente degradar el código VB.NET manualmente a VBA, dándome una pureza Solución VBA. Después de tener problemas para compilar con cualquier compilador .NET, abandoné esta ruta.

Asumiendo que podría haber obtenido una biblioteca .NET en funcionamiento, también podría haber usado ExcelDna ( http://www.codeplex.com/exceldna ), un complemento de código abierto de Excel para facilitar la integración del código .NET.

Mi última idea fue alojar un objeto de Internet Explorer, enviar el código fuente de JavaScript y llamarlo. Incluso si hiciera que esto funcionara, supongo que sería muy lento y desordenado.

ACTUALIZACIÓN: ¡Solución encontrada!

Utilicé el método WSC descrito a continuación por la respuesta aceptada. Tuve que cambiar el código de WSC un poco para limpiar los diffs y devolverme una matriz de matrices compatible con VBA:

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(); }

Registré el WSC y funcionó bien. El código en VBA para llamarlo es el siguiente:

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

(Traté de mantener un objWMIServicio global único y objDiff para no tener que crear / destruir estos para cada celda, pero no parecía hacer una diferencia en el rendimiento).

Luego escribí mi macro principal. Toma tres parámetros: un rango (una columna) de valores originales, un rango de valores nuevos y un rango donde el diff debe volcar los resultados. Se supone que todos tienen la misma cantidad de filas, no tengo ninguna verificación de errores importante aquí.

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

Las siguientes tres líneas aceleran la actualización sin estropear el modo de cálculo preferido del usuario más adelante:

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

Borrar los difs anteriores, si los hay, es importante:

Erase diffs

Esta prueba es un atajo visual para mis usuarios, así que está claro cuando no hay ningún cambio:

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

Combine todo el texto como el valor de celda delta, si el texto fue idéntico, insertado o eliminado:

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

Debe establecer el valor antes de comenzar el formateo:

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

Aquí está el código que interpreta los dif y formatea la celda delta:

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

Hay algunas oportunidades para la optimización, pero hasta ahora está funcionando bien. Gracias a todos los que ayudaron!


Mi sugerencia sería que hagas lo que hagas, lo envuelves en un contenedor COM. VBA funciona mejor con objetos COM para que pueda compilar como un Componente .NET y luego exponer como un objeto COM utilizando la funcionalidad de interoperabilidad de .NET.

Como alternativa, también podría considerar el uso de objetos de Windows Scripting Host para ejecutar un archivo Javascript y devolverle el resultado.



El enfoque más simple puede ser incorporar la lógica Javascript diff en un componente COM directamente usando Javascript. Esto es posible a través de algo llamado " Componentes de Windows Script ".

Aquí hay un tutorial sobre cómo crear WSCs .

Un componente de script de Windows es un componente COM que se define en el script. La interfaz del componente es a través de COM, lo que significa que es compatible con VBA. La lógica se implementa en cualquier lenguaje compatible con Windows Scripting Hosting, como JavaScript o VBScript. El WSC se define en un solo archivo XML, que integra la lógica, el componente ID de clase, los métodos, la lógica de registro, etc.

También hay una herramienta disponible para ayudar a crear una CSM . Básicamente se trata de un tipo de asistente que le hace preguntas y rellena la plantilla XML. Yo mismo, comencé con un archivo .wsc de ejemplo y lo edité a mano con un editor de texto. Es bastante auto explicativo.

Un componente COM definido de esta manera en el script (en un archivo .wsc) se puede llamar al igual que cualquier otro componente COM, desde cualquier entorno que pueda bailar con COM.

ACTUALIZACIÓN : Me tomé unos minutos y produje el WSC para GoogleDiff. Aquí está.

<?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>

Para usar esa cosa, debes registrarla. En Explorer, haz clic derecho sobre él y selecciona "Registrarse". o, desde la línea de comando: archivo regsvr32: / c: / scripts / GoogleDiff.wsc

No intenté usarlo desde VBA, pero aquí hay algún código de VBScript que usa el componente.

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