El siguiente es un estudio de caso sobre el uso del Depurador JSL para resolver un problema. Esto se basa en un script real con el problema especificado. Si desea ver el problema en contexto, creé un script, muy simplificado del original, que muestra el problema. Si desea "seguir el juego", puede descargar DebuggerDemo-SolvingProblems.jsl desde el intercambio de archivos JMP (se requiere un perfil SAS gratuito para descargar).
Aunque describo el script original, los fragmentos de código y las imágenes son todos de este script de ejemplo. ¡Seguir a lo largo!
El problema
El otro día, un guionista de JSL que tenía un problema con un guión me fue dirigido a mí en busca de ayuda. Su script funcionó bien en inglés, pero un probador que ejecuta su script en chino simplificado obtuvo errores.
El problema parecía estar relacionado con la forma en que se manejaban las cadenas en inglés en comparación con el chino: Específicamente, comillas escapadas ( \! " ) estaban siendo excluidos.
En inglés, aquí hay una cadena de muestra que fue construida:
"dt << Seleccione Where (dt: Numbers == 45 & dt: Pick Strings == \!" South \! ")"
En chino, la cuerda se veía así:
"dt << Seleccione Where (dt: Numbers == 45 & dt: Pick Strings == South)"
Nota la falta \! "... \!" alrededor Sur , lo que provocó errores cuando se analizó la cadena y ese valor no citado no se pudo resolver.
¿Hubo un error en JMP al manejar citas dentro de cadenas en otros idiomas además del inglés?
Primera vista
Ella me envió el script y los datos necesarios para ejecutarlo. El guión tenía poco menos de 900 líneas y produjo un informe interactivo. Las primeras 130 líneas se configuraron, las líneas 131-886 definieron expresiones, y luego el resto de la secuencia de comandos usó esas expresiones.
Lo primero que hice fue ejecutar el script en inglés y luego en chino, para ver si tenía el mismo problema. Yo si. Luego lo publiqué en francés, lo que confirmó que el problema estaba relacionado con cualquier idioma que no fuera el inglés, no solo el chino. Corrí el resto de mis pruebas en inglés y francés, porque el francés es más fácil de leer que el chino.
PROPINA: Es fácil cambiar el idioma en el que estás ejecutando JMP en Windows. Seleccione Archivo> Preferencias y seleccione la categoría Específica de Windows. En la parte superior, seleccione un idioma en Mostrar idioma. En Macintosh, salga primero de JMP y luego abra Preferencias del sistema (en el menú Apple) y seleccione la categoría Idioma y texto. Arrastre un nuevo idioma a la parte superior de la lista. ¡No cierres esta ventana! Establece el idioma para tu computadora. Inicie JMP y se ejecutará en el primer idioma de la lista. Cuando termine, salga de JMP y arrastre el inglés (o el idioma que normalmente usa en su computadora) a la parte superior. Ahora es seguro cerrar la ventana de Preferencias del Sistema.
Hubo varias líneas que construyeron la cadena de arriba, y todas se basaron en una codificación bastante compleja que habría sido difícil y lento ejecutar línea por línea, entrando y saliendo de múltiples expresiones, y entendiendo lo que estaba viendo.
La ejecución de solo las líneas de construcción de cadenas apropiadas (después de haber ejecutado el script una vez para inicializar todas esas variables) dio los mismos resultados en todos los idiomas, con las comillas de escape que se utilizan correctamente. Sin embargo, las líneas que formaron la cadena usaron valores de dos tablas de datos más una tercera que se construyó a partir de las dos primeras, y fue muy difícil decir de un vistazo dónde se crearon y llenaron todas las variables que se estaban usando.
En otras palabras, ¡este fue un trabajo para el Depurador JSL!
Entrar en el depurador JSL
Ejecutando JMP en inglés, abrí el script y hice clic en Depurar. Como ya había ejecutado el script, todas sus variables se enumeraban en Globales. Y había muchos de ellos, demasiados para rastrearlos a medida que avanzaba en el guión. (También podría haber descubierto esto ejecutando Mostrar Globales () y viendo crecer el tronco muy largo.
Eso era todo lo que necesitaba saber en ese momento, así que abandoné el Depurador JSL y cerré y reinicié JMP para que mi entorno estuviera completamente limpio. Abrí el script y volví a iniciar el depurador.
Solo me interesaba la cadena que se estaba construyendo, así que agregué esa variable a mi Lista de observación. Para hacerlo, seleccioné la variable en el script como se muestra en el Depurador de JSL, hice clic derecho y seleccioné Agregar vigilancia.

Agregué un punto de interrupción en la primera línea después de que se completara la parte de configuración (Línea 131 en el original; Línea 34 en mi muestra), y otro en la primera línea de instrucción "real" después de que se crearon todas las expresiones (Línea 887 en el original; esto no existe en mi muestra). Para hacerlo, hice clic al lado del número de línea en el script que se muestra en el depurador.

PROPINA: Un punto de interrupción solo funcionará si lo coloca en una línea que realiza alguna acción. Se ignorará un punto de interrupción en una línea en blanco, una línea que solo contenga un paréntesis cerrado o una línea que esté comentada.
Ejecuté la primera parte de "configuración" y vi que mi variable de cadena aún no se había creado. Aprendí eso con un solo clic, ¡mucho más rápido de lo que habría ejecutado el script manualmente línea por línea!
Corrí la segunda parte, que simplemente creó todas las expresiones.
Ahora era el momento de la acción.
La "carne" de la secuencia de comandos estaba contenida en la parte inferior de la secuencia de comandos original, en solo 10 líneas. La primera parte fue un bucle que llamó un par de expresiones (que llamó expresiones, que llamó expresiones, etc.). Utilicé el botón Paso a paso para ingresar a cada expresión, para averiguar qué estaba sucediendo.
PROPINA: Usando Paso a Paso cuando una expresión, función definida por el usuario, o Incluir () son llamados, ejecuta ese código en su totalidad, devuelve su resultado y coloca el punto de ejecución en la siguiente línea. Si no necesita pasar de línea en línea, esta es una forma rápida de omitir lo que no necesita. Por otro lado, a veces es necesario ver exactamente qué hace esa expresión, función o script incluido. Utilice Paso a paso en su lugar, y podrá recorrer ese fragmento de código línea por línea.
Resultados
Lo que descubrí fue que cada pieza de la cadena fue construida dentro de un Si () expresión: si la columna con la información era un carácter, entonces el valor fue citado con las comillas escapadas; de lo contrario, el valor no fue citado.
Esto también significó que, de casi 900 líneas de código, solo me interesaba una pequeña parte de 19 líneas (que, sin embargo, dependía de las otras 800+). Estas líneas se recrean (y simplifican) en las Líneas 38 - 54 en mi muestra.
Cambié JMP para ejecutarlo en francés, cerré y reinicié, y volví a pasar por el depurador.
De repente, todo estaba claro ...
JMP está localizado! (¿Quien sabe?)
El problema no fue con las asignaciones que construyeron la cadena. El problema que vi inmediatamente con el depurador es que en francés, la condición dentro del Si () expresión que determinó si la columna era un carácter determinado que la columna era no personaje. Para las columnas de caracteres, la secuencia de comandos ejecutó un punto de código diferente en francés que en inglés.
De hecho, la condición en francés siempre regresaría. 0 . La pieza de condición de la Si () La expresión es esta (líneas 40 y 48 en mi muestra):
Analizar gramaticalmente ( "dt:" || ColumnNames El estoCol ] ) << Obtener tipo de datos () == "Personaje"
En inglés, columna << Obtener tipo de datos () devoluciones "Personaje" para una columna de caracteres. En francés, vuelve. "Caractère" , lo que nunca se evaluará por ser igual a "Personaje" .
columna << Obtener tipo de datos () Siempre devuelve una respuesta localizada.
Dado que la columna en cuestión nunca se determinó que fuera igual a "Personaje" cuando se ejecuta en chino (o en francés o en cualquier otro idioma que no sea inglés que admita JMP), la cadena se construyó como si el valor de la celda fuera numérico. Y esa fue la razón por la que la cadena en inglés se había escapado de las comillas y la cadena en chino no.
Nota: Aunque el Depurador JSL no muestra los resultados del << Obtener tipo de datos () mensaje - solo el resultado de la comparación - podría salir fácilmente del depurador y seleccionar y ejecutar Analizar gramaticalmente ( "dt:" || ColumnNames El estoCol ] ) << Obtener tipo de datos () para ver lo que en realidad fue devuelto. El depurador me permitió encontrar el problema rápidamente y sin dolor.
Llamada a la acción
No hay ningún error en JMP: esto funciona como está diseñado. El script solo necesita un pequeño cambio para funcionar en cualquier idioma.
Hay más de un enfoque para hacer que el script sea amigable en todos los idiomas. ¿Qué harías? Agregaré el enfoque que tomamos a los comentarios en una semana o dos.