
Manejar la mayor parte del texto en UTF-8 en lugar de cadenas TeX tiene muchas ventajas, no solo es fácil para la vista, los dedos y los editores, sino que también resulta muy fácil enviar su texto a los correctores ortográficos, correctores gramaticales y otros analizadores. .... imagínate escribiendo esta cadena
ĄąĆćĘę£łŃńÓóŚś-źŻż
Usar estrategias simples de búsqueda/reemplazo puede ser desastroso debido a cosas como:
\def\L{\matbb{L}}
dejando errores enterrados en lo más profundo de los archivos convertidos. Sin mencionar cuán profundamente podría quedar enterrada la definición del personaje.
Entiendo que uno puede identificar de forma única a los personajes (como enaquí) y esopandoc,tex4htyhiperreferenciaabordar este problema en algún nivel. Mi pregunta es: ¿Qué tan viable sería implementar dicho convertidor en el propio TeX?
(agregado por David)
aporte:
\documentclass{article}
\newcommand\zzz{hello}
\begin{document}
\L\"{o}\"{o}\c{k} \zzz
\renewcommand\L{LLL}
\renewcommand\"[1]{#1#1}
\renewcommand\c{c}
\L\"{o}\"{o}\c{k} \zzz
\end{document}
Convertido al formulario con texto UTF-8, pero se ejecuta el uso de macros:
\documentclass{article}
\newcommand\zzz{hello}
\begin{document}
Łööķ \zzz
\renewcommand\L{LLL}
\renewcommand\"[1]{#1#1}
\renewcommand\c{c}
\L\"{o}\"{o}\c{k} \zzz
\end{document}
Respuesta1
En primer lugar, si prefiere una entrada como ĄąĆćĘę£łŃńÓóŚś-źŻż
en su .tex
archivo, simplemente puede escribirla (o pegarla). Todo lo que necesita es \usepackage[utf8]{inputenc}
si está usando pdfTeX, o ni siquiera eso si usa un motor compatible con Unicode (XeTeX o LuaTeX). ). Por ejemplo, lo siguiente simplemente funciona (cuando se compila con xelatex
):
\documentclass{article}
\begin{document}
ĄąĆćĘę£łŃńÓóŚś-źŻż
\end{document}
Si el problema es que no tiene una distribución de teclado conveniente (o fácil de recordar) para escribir eso, entonces prefiere escribir usando las macros TeX (pero aún así prefiere que el archivo contenga caracteres como los anteriores), entonces esto es simplemente una cuestión de configurar su editor o sistema de entrada. Por ejemplo (sugerido en elcomentariospor el usuario Loop Space), Emacs puede hacer esto, con M-x set-input-method RET TeX
: cuando presionas las teclas \=o
de tu teclado, lo que se escribe en el archivo esō
. No es necesario utilizar Emacs; Este tipo de característica también está disponible en métodos de entrada como UIM (ejemplo).
Así que no veo ninguna razón para usar TeX para realizar dicha conversión, si estás creando el .tex
archivo: sería mejor encontrar una manera de insertar tus caracteres preferidos en primer lugar.
Sin embargo, la pregunta puede tener sentido si está trabajando con un .tex
archivo creado por otra persona (y está bien que cambie el archivo), o si lo creó usted mismo antes de tener esta preferencia.
Lo principal que ofrece el uso de TeX (en lugar de una simple búsqueda y reemplazo en su editor) es la capacidad de saber cuándo las definiciones de macros gustan \L
y \O
han cambiado. Este es también el problema ilustrado en la pregunta.
Entonces, para resolver esto, tengo la siguiente solución usando la introspectiva (también conocida comoreflexivo) capacidades que vienen con LuaTeX: específicamente, token.get_macro
que nos permite ver las definiciones de macros y la process_input_buffer
devolución de llamada que nos permite examinar cada línea de entrada (y cambiarla si queremos). La idea es:
- Antes de que comience el texto, registre las definiciones "originales" de todas las macros de reemplazo de caracteres conocidas (
\L
,\"
,\c
, etc.). Esto nos permite saber cuándo se han redefinido. - Para cada línea en la entrada, busque aquellas macros que ocurren en la línea,comprobar si sus definiciones no han cambiadoy (si es así) reemplácelos junto con sus argumentos con los reemplazos apropiados.
Entonces, con el ejemplo de la pregunta, en un archivo llamado digamos mwe.tex
:
\documentclass{article}
\directlua{dofile('rewrite.lua')}
\newcommand\zzz{hello}
\begin{document}
\L\"{o}\"{o}\c{k} \zzz
\renewcommand\L{LLL}
\renewcommand\"[1]{#1#1}
\renewcommand\c{c}
\L\"{o}\"{o}\c{k} \zzz
\end{document}
(tenga en cuenta la \directlua{dofile(...)}
línea que se agregó), puede ejecutar lualatex mwe.tex
(algunas líneas recortadas):
9:41:29:~/tmp% lualatex mwe.tex
This is LuaTeX, Version 1.0.4 (TeX Live 2017)
...
The original definition of #\L# is \TU-cmd \L \TU\L
The original definition of #\c# is \TU-cmd \c \TU\c
The original definition of #\"# is \TU-cmd \"\TU\"
...
Processing line: \begin{document}
--> Rewrote line to \begin{document}
...
Processing line: \L\"{o}\"{o}\c{k} \zzz
--> Rewrote line to Łööķ \zzz
Processing line:
--> Rewrote line to
Processing line: \renewcommand\L{LLL}
^ This line contains a \def or \newcommand or \renewcommand. Not rewriting.
...
Processing line: \L\"{o}\"{o}\c{k} \zzz
--> Rewrote line to \L\"{o}\"{o}\c{k} \zzz
Y encontrarás un mwe.rewritten.tex
archivo que contiene:
\newcommand\zzz{hello}
\begin{document}
\relax
Łööķ \zzz
\renewcommand\L{LLL}
\renewcommand\"[1]{#1#1}
\renewcommand\c{c}
\L\"{o}\"{o}\c{k} \zzz
\end{document}
\relax
donde se puede ver que solo han ocurrido los reemplazos que deberían haber ocurrido. El archivo Lua (llamado rewrite.lua
arriba) que hace que esto suceda es:
print('')
rewritten_file = io.open(tex.jobname .. '.rewritten.tex', 'w')
funny_noarg = {
["\\L"] = "Ł",
-- Define similarly for \oe \OE \ae \AE \aa \AA \o \O \l \i \j
}
funny_nonletter = {
['\\"'] = function(c) return c .. "̈" end,
-- Define similarly for \` \' \^ \~ \= \.
}
funny_letter = {
["\\c"] = function(c) return c .. "̧" end,
-- Define similarly for \u \v \H \c \d \b \t
}
orig_defs = {}
function populate_orig_defs()
function set_def(s)
definition = token.get_macro(s:sub(2))
orig_defs[s] = definition
print('The original definition of #' .. s .. '# is ' .. definition)
end
for s, v in pairs(funny_noarg) do set_def(s) end
for s, v in pairs(funny_letter) do set_def(s) end
for s, v in pairs(funny_nonletter) do set_def(s) end
end
populate_orig_defs()
function literalize(s)
-- The string s, with special characters escaped, in a format safe for using inside gsub.
-- https://stackoverflow.com/questions/1745448/lua-plain-string-gsub#comment18401212_1746473
return s:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0")
end
function replace(s)
print('Processing line: ' .. s)
if s:find([[\def]]) ~= nil or s:find([[\newcommand]]) ~= nil or s:find([[\renewcommand]]) ~= nil then
print(' ^ This line contains a \\def or \\newcommand or \\renewcommand. Not rewriting.')
rewritten_file:write(s .. '\n')
return nil
end
for k, v in pairs(funny_noarg) do
-- followed by a nonletter. TODO: Can use the catcode tables.
if token.get_macro(k:sub(2)) == orig_defs[k] then
s = s:gsub(literalize(k) .. '([^a-zA-Z])', function(capture) return v .. capture end)
end
end
for k, v in pairs(funny_letter) do
-- followed by a letter inside {}. TODO: Can use the catcode tables, also can support \c c, for example.
if token.get_macro(k:sub(2)) == orig_defs[k] then
s = s:gsub(literalize(k) .. '{(.)}', v)
end
end
for k, v in pairs(funny_nonletter) do
-- followed by a letter inside {}. TODO: We could also support \"o for example.
if token.get_macro(k:sub(2)) == orig_defs[k] then
s = s:gsub(literalize(k) .. '{(.)}', v)
end
end
print(' --> Rewrote line to ' .. s)
rewritten_file:write(s .. '\n')
return nil
end
luatexbase.add_to_callback('process_input_buffer', replace, 'Replace some macros with UTF-8 equivalents')
Como esto es sólo una prueba de concepto y no un sistema de calidad de producción, tomé algunos atajos que puedes completar si estás interesado en seguir este enfoque:
- Solo se enumeran los equivalentes Unicode para algunas de las macros con acento o caracteres especiales de TeX.
- Debe volver a insertar la
\documentclass{article}
línea (y, de hecho, todo lo que tenga antes de la\directlua{dofile(…)}
línea). (Para divertirte, puedes intentar mover la líneaantes\documentclass
y mira lo que pasa.) - Probablemente quieras tener esta línea después de todas
\usepackage
las líneas, tal vez al comienzo de\begin{document}
. (Si ha probado lo anterior, sabrá por qué). - Debes eliminar la
\relax
línea al final (probablemente podríamos hacer que esto no aparezca...) - Se supone que el archivo de entrada contiene la convención LaTeX
\={o}
y no\=o
; con unas cuantas líneas más podríamos apoyar también a este último. De manera similar si en lugar de\c{k}
tenemos\c k
o\c {k}
, etc. - Ignora por completo (no reemplaza nada) las líneas que contienen
\def
o\newcommand
; en cambio, si quisiéramos (¡si el archivo de entrada estuviera tan mal escrito!), podríamos saltar hasta el final\def
o lo que sea, y procesar el resto. - Se supone que (para saber cuándo
\o
termina una secuencia de control como) que las “letras” sona-zA-Z
; es posible que desee agregar algo@
a esa lista y, de hecho, podríamos usar la definición exacta de "letra" bajo el régimen de código cat activo en ese momento; LuaTeX también proporciona eso.
Tenga en cuenta que incluso si normalmente compila su archivo con pdfTeX o XeTeX, puede usar LuaTeX solo para esta conversión y volver a usar pdfTeX/XeTeX en el archivo convertido.