Tengo un archivo .scpt de AppleScript, activado por una combinación de teclas en FastScripts.app, que funciona como un diccionario de sinónimos. El script busca la palabra seleccionada en una lista preformateada y, si la palabra se encuentra en esta lista, muestra los sinónimos de esta palabra al usuario 1 .
Esta lista está contenida en un archivo de texto sin formato (.txt). La lista ya está formateada en list
formato AppleScript. Me gustaría que mi archivo .scpt pueda aceptar este texto como una lista verdadera 2 .
Es importante señalar que el archivo .txt contiene 2,5 millones de palabras 3 .
Es por eso que no copio simplemente el contenido del archivo .txt en el archivo .scpt, a pesar de que el archivo de texto es 100 % estático y nunca se modificará. Insertar el texto directamente en mi secuencia de comandos traería consigo un retraso y una lentitud considerables mientras edito y compilo mi archivo .scpt en Script Editor.app.
Script Editor.app se congelaba cada vez que intentaba leer el archivo .txt. El problema es que Script Editor lee en la memoria un archivo de texto dado en su totalidad, en lugar de transmitir los contenidos de una manera más eficiente. Entonces, dividí este archivo de texto en 10 archivos de texto más pequeños 4 , cada nuevo archivo .txt contiene alrededor de 250 000 palabras.
Por supuesto, con 250.000 palabras, los archivos de texto siguen siendo extremadamente grandes (desde cualquier punto de vista).
Aquí hay un ejemplo (muy resumido) de cómo se ve el contenido de cada archivo de texto:
{{"exaltación","galardón","adulación","avanzar","adelanto"},{"exaltado","aventar","ganador"},{"examen","audición","libro azul" ,"examen","examen","final","examen","test","ensayo","tripos","viva","escrito","examen escrito"},{"examen","Pap prueba","Método socrático","ventilación","análisis","diagnóstico anatómico","evaluación","elaboración","escrito","examen escrito"},{"examinar","aire", "analizar","valorar","arquetipo","dormido","evaluar","lienzo","caso"},{"examinador","analista","analizador","preguntador"},{"examinando","analítico","examinatorio","exploratorio"},{"ejemplo","advertencia"," amonestación","alarma","arquetipo"},{"exasperado","molesto","vex","exagerado","preocupación"},{"exasperado","agravado","amplificado","enojado ","molesto"},{"exasperante","molesto","molesto","molesto"}}alarma","arquetipo"},{"exasperado","atormentado","vex","exasperado","preocupado"},{"exasperado","agravado","amplificado","enojado","molesto "},{"exasperante","molesto","molesto","molesto"}}alarma","arquetipo"},{"exasperado","atormentado","vex","exasperado","preocupado"},{"exasperado","agravado","amplificado","enojado","molesto "},{"exasperante","molesto","molesto","molesto"}}
Como puede ver, el contenido del archivo de texto es una lista anidada 5 que está organizada de la misma manera que AppleScript formatea un archivo list
. Cada archivo de texto no contiene saltos de línea ni párrafos.
Estoy buscando un método para incluir esta lista en mi AppleScript, con la menor latencia posible 6 . Es por eso que lo formateé previamente. Por lo tanto, la velocidad es clave .
Notas al pie:
1. La secuencia de comandos de mi diccionario de sinónimos es similar a la función de diccionario de sinónimos integrada que existe en Microsoft Word. Una diferencia notable es que mi script funciona en todo el sistema.
2. Por lista verdadera , quiero decir que puedo llamar, por ejemplo, item 12
a esta lista más adelante en mi AppleScript.
3. Mi fuente para los datos del tesauro es el Tesauro "Moby" de Grady Ward. Encontré esta base de datos de esta respuesta: Buscando datos de tesauro programandonet.com
4. Tuve que usar Hex Fiend.app para cortar el archivo de texto y pegarlo en un nuevo archivo de texto. No pude editar el archivo en TextEdit.app, sin que TextEdit se congelara.
5. La lista exterior contiene cada entrada del tesauro. Las listas internas contienen todos los sinónimos de esa entrada. El primer elemento de cada lista interna es el título de la entrada. Tanto la lista exterior como cada lista interior están ordenadas alfabéticamente (con la excepción de la primera palabra de cada lista interior, porque, de nuevo, esta palabra es el título de la entrada).
6. Entiendo que incluso el método más rápido tendrá varios segundos de latencia, ya que el archivo de texto es muy grande.
Obviamente, no sé el alcance total de lo que está haciendo o cómo tiene otras cosas codificadas, ya que no proporcionó todos los detalles y el código; sin embargo, tomaría un enfoque diferente.
Descargué el Moby Thesaurus de la página vinculada en su pregunta y realicé las siguientes acciones en él.
mthes.tar.Z
archivo../mthes/mobythes.aur
archivo en TextWrangler y notó dos cosas para cambiar.
Tenga en cuenta que si bien pude hacer estos cambios en TextWrangler, prefiero usar Terminal y lo hice con el siguiente comando:
tr "\r" "\n" < mobythes.aur | sed -E 's/[,]{1,}$//' > mobythes.txt
Lo que tomó literalmente un segundo (ya que en realidad prediqué el comando anterior con time
, por curiosidad). Ahora que el mobythes.aur
archivo ha sido procesado, guardado mobythes.txt
y copiado en mi carpeta Documentos, usaré este nuevo archivo CSV sin formato tal como está, para consultar la cadena de búsqueda en busca de una coincidencia con el primer campo de cada registro y devolver el registro, sin el primer campo, como una lista para elegir en AppleScript. Encontré que este método es extremadamente rápido, mientras buscaba "acercar" el último registro en el archivo CSV, solo tomó un segundo regresar y crear la lista para ese registro sobre la marcha.
En AppleScript Editor utilizo el siguiente código para compararlo con el archivo CSV simple como un solo archivo que contiene las 30 260 líneas con 2,5 millones de sinónimos y palabras relacionadas.
set AppleScript's text item delimiters to ""
set theMobyThesaurus to POSIX path of (path to documents folder) & "mobythes.txt"
set theSearchString to the text returned of (display dialog "Find synonyms for:" default answer "" buttons {"Cancel", "Search"} default button 2 with title "Search Moby Thesaurus")
if theSearchString is not equal to "" then
try
set theSearchResults to (do shell script "grep -i -m 1 '^" & theSearchString & ",' " & theMobyThesaurus)
on error
display dialog "No match for \"" & theSearchString & "\" available." buttons {"OK"} default button 1
return
end try
if theSearchResults is not equal to "" then
set AppleScript's text item delimiters to ","
set theSynonymsList to items 2 thru -1 of text items of theSearchResults as list
set AppleScript's text item delimiters to ""
choose from list theSynonymsList with prompt "Choose a synonym for: " & linefeed & theSearchString
if the result is not false then
set theChosenWord to (item 1 of the result)
end if
end if
end if
En este ejemplo, suponiendo que se hizo una coincidencia de búsqueda y no se canceló nada, la theChosenWord
variable ahora contiene lo que se eligió de la lista mostrada y se puede procesar más según sea necesario o deseado.
Tenga en cuenta que, por supuesto, este es un código estrictamente de ejemplo para fines de prueba y deberá adaptarse a su escenario de caso de uso al tiempo que incorpora el manejo de errores adecuado según sea necesario.
Creo que esta será la forma más rápida mientras deja el Tesauro de Moby como un solo archivo CSV, y probablemente sea más rápido que cualquier método que haya probado hasta ahora.
>
en la siguiente línea. No estoy familiarizado con Terminal, así que no sé cuál es el problema.'
fuera de lugar sed
. Arreglé el error tipográfico.choose from list
diálogo. (En caso de que sienta curiosidad, el script mostrará keystroke
el sinónimo que elija el usuario, sobrescribiendo la palabra original que se seleccionó). No puedo agradecerles lo suficiente.grep
código distingue entre mayúsculas y minúsculas. Por ejemplo, si theSearchString
es Zoom
, no aparecerán coincidencias. Del mismo modo, una búsqueda de socratic
no produce resultados. ¿Sabes cómo arreglar esto, para que theSearchString
no importe el caso de los personajes?man grep
y presione Intro, o simplemente escriba grep
y haga clic con el botón derecho en grep
y seleccione Open man page
. He actualizado la respuesta. Por cierto, como con muchos comandos, las opciones se pueden concatenar, es decir, se -i -m 1
pueden escribir -im 1
pero no -m 1i
.set theSynonymsList ...
comando.Había ideado una solución antes de que el usuario 3439894 publicara su respuesta.
A pesar de que la solución de user3439894 es superior a mi solución en todos los sentidos, creo que también puedo publicar mi código, aunque solo sea para resaltar el rápido tiempo de respuesta de la solución de user3439894 .
Aquí están las dos modificaciones que hice al archivo fuente, mobythes.aur , para mi solución:
Convertí el archivo .aur en un archivo .txt, simplemente cambiando el nombre de la extensión del archivo en Finder.
Inserté (1) retorno de carro antes del primer carácter del archivo .txt (en caso de que el usuario alguna vez busque la primera entrada del diccionario de sinónimos, es decir, a cappella
).
Me di cuenta de que estaba ladrando en el árbol equivocado en mi publicación original: no hay necesidad (ni beneficio, en realidad) de formatear previamente el contenido del archivo .txt en el formato de AppleScript, list
dentro del archivo mismo. Por lo tanto, no modifiqué la estructura delimitadora original del archivo en absoluto (de la forma en que lo había hecho en mi publicación original).
display dialog "Find synonyms of:" default answer ""
set theSearchQuery to text returned of the result
-- Referencing the default delimiters of the "mobythes.txt" file:
set theOuterListDelimiter_oneCarriageReturn to (ASCII character 13)
set theInnerListDelimiter_oneComma to ","
set theSearchQueryAsAThesaurusEntry to (theOuterListDelimiter_oneCarriageReturn & theSearchQuery & theInnerListDelimiter_oneComma)
set theThesaurusAsString to (read POSIX file "/Users/Me/Desktop/mobythes.txt")
if theThesaurusAsString contains theSearchQueryAsAThesaurusEntry then
set theSynonymsAsText to extractBetween(theThesaurusAsString, theSearchQueryAsAThesaurusEntry, theOuterListDelimiter_oneCarriageReturn)
set theSynonymsInList to splitStringIntoList(theSynonymsAsText, theInnerListDelimiter_oneComma)
choose from list theSynonymsInList
else
display dialog "No thesaurus entry exists for \"" & theSearchQuery & "\"!"
end if
-- Subroutines:
to extractBetween(SearchText, startText, endText)
-- Source: http://macscripter.net/viewtopic.php?id=24725
set tid to AppleScript's text item delimiters -- save them for later.
set AppleScript's text item delimiters to startText -- find the first one.
set endItems to text of text item -1 of SearchText -- everything after the first.
set AppleScript's text item delimiters to endText -- find the end one.
set beginningToEnd to text of text item 1 of endItems -- get the first part.
set AppleScript's text item delimiters to tid -- back to original values.
return beginningToEnd -- pass back the piece.
end extractBetween
on splitStringIntoList(theString, theDelimiter)
-- Source: http://erikslab.com/2007/08/31/applescript-how-to-split-a-string/
-- save delimiters to restore old settings:
set oldDelimiters to AppleScript's text item delimiters
-- set delimiters to delimiter to be used:
set AppleScript's text item delimiters to theDelimiter
-- create the array:
set theArray to every text item of theString
-- restore the old setting:
set AppleScript's text item delimiters to oldDelimiters
-- return the result:
return theArray
end splitStringIntoList
Por curiosidad, realicé un "tiroteo" de los tiempos de ejecución entre el enfoque de user3439894 y mi enfoque.
Comenté cada diálogo en nuestras dos soluciones. Configuré el término de búsqueda de prueba como la cadena fija, "planet"
.
Ingresando time osascript /Users/Me/Desktop/MyOriginalSolution.scpt
en Terminal.app devolvió:
real 0m1.257s
user 0m0.728s
sys 0m0.409s
Entrando time osascript /Users/Me/Desktop/user3439894Solution.scpt
devuelto:
real 0m0.250s
user 0m0.193s
sys 0m0.030s
Según esta prueba, la solución de user3439894 es 5 veces más rápida que la mía, con una diferencia de 1,007 segundos.
klanomath
esfera de rubik
klanomath
esfera de rubik