
Lidar com a maior parte do texto em UTF-8 em vez de strings TeX tem muitas vantagens, não é apenas fácil para os olhos, dedos e editores, mas também torna-se muito fácil alimentar seu texto para corretores ortográficos, verificadores gramaticais e outros analisadores .... imagine escrever esta string
ĄąĆćĘę£łŃńÓóŚś-źŻż
Usar estratégias simples de pesquisa/substituição pode ser desastroso por causa de coisas como:
\def\L{\matbb{L}}
deixando erros enterrados profundamente nos arquivos convertidos. Sem mencionar o quão profunda a definição do personagem poderia estar enterrada.
Eu entendo que é possível identificar os personagens de maneira única (como emaqui) e essapandoc,texto4htehiperreflidar com esse problema em algum nível. Minha pergunta é: Quão viável seria implementar tal conversor no próprio TeX?
(adicionado por David)
entrada:
\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 para formulário com texto UTF-8 executado, mas com uso de macro em vigor:
\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}
Responder1
Em primeiro lugar, se você preferir a entrada como ĄąĆćĘę£łŃńÓóŚś-źŻż
no seu .tex
arquivo, então você pode simplesmente digitar (ou colar). Tudo que você precisa é \usepackage[utf8]{inputenc}
se estiver usando pdfTeX, ou nem mesmo se estiver usando um mecanismo compatível com Unicode (XeTeX ou LuaTeX ). Por exemplo, o seguinte funciona (quando compilado com xelatex
):
\documentclass{article}
\begin{document}
ĄąĆćĘę£łŃńÓóŚś-źŻż
\end{document}
Se o problema é que você não tem um layout de teclado conveniente (ou memorável) para digitar isso, então você prefere digitar usando as macros TeX (mas ainda prefere que o arquivo contenha caracteres como os acima), então é simplesmente uma questão de configurar seu editor ou sistema de entrada. Por exemplo (sugerido nocomentáriospelo usuário Loop Space), o Emacs pode fazer isso, com M-x set-input-method RET TeX
: quando você pressiona as teclas \=o
do teclado, o que é digitado no arquivo é ō
. Você não precisa usar o Emacs; esse tipo de recurso também está disponível em métodos de entrada como UIM (exemplo).
Portanto, não vejo razão para usar o próprio TeX para fazer tal conversão, se você estiver criando o .tex
arquivo: seria melhor encontrar uma maneira de inserir seus caracteres preferidos em primeiro lugar.
No entanto, a pergunta pode fazer sentido se você estiver trabalhando com um .tex
arquivo criado por outra pessoa (e não há problema em alterar o arquivo) ou criado por você mesmo antes de ter essa preferência.
A principal coisa que o uso do TeX (em vez de simplesmente pesquisar e substituir em seu editor, digamos) oferece é a capacidade de saber quando as definições de macros \L
foram \O
alteradas. Este também é o problema ilustrado na pergunta.
Então, para resolver isso, tenho a seguinte solução usando o introspectivo (também conhecido comoreflexivo) habilidades que vêm com o LuaTeX: especificamente, token.get_macro
que nos permite ver as definições de macros, e o process_input_buffer
retorno de chamada que nos permite examinar cada linha de entrada (e alterá-la se quisermos). A ideia é:
- Antes de o texto começar, registre as definições “originais” de todas as macros de substituição de caracteres conhecidas (
\L
,\"
,\c
, etc). Isso nos permite saber quando eles foram redefinidos. - Para cada linha na entrada, procure as macros que ocorrem na linha,verifique se suas definições não mudarame (em caso afirmativo) substitua-os e seus argumentos pelas substituições apropriadas.
Então, com o exemplo da pergunta, em um arquivo chamado 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}
(observe a \directlua{dofile(...)}
linha que foi adicionada), você pode executar lualatex mwe.tex
(algumas linhas cortadas):
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
E você encontrará um mwe.rewritten.tex
arquivo contendo:
\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
onde você pode ver que apenas as substituições que deveriam ter acontecido aconteceram. O arquivo Lua (chamado rewrite.lua
acima) acima que faz isso acontecer é:
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 esta é apenas uma prova de conceito e não um sistema de qualidade de produção, tomei alguns atalhos que você pode preencher se estiver interessado em seguir esta abordagem:
- Listei apenas os equivalentes Unicode para alguns macros de acento ou caracteres especiais do TeX
- Você precisa reinserir a
\documentclass{article}
linha (e de fato tudo o que você tem antes da\directlua{dofile(…)}
linha). (Para se divertir, você pode tentar mover a linhaantes\documentclass
e veja o que acontece.) - Você provavelmente deseja ter esta linha depois de todas
\usepackage
as linhas, talvez no início de\begin{document}
. (Se você tentou o procedimento acima, saberá por quê.) - Você precisa remover a
\relax
linha no final (provavelmente poderíamos fazer com que isso não aparecesse…) - Ele assume que o arquivo de entrada contém a convenção LaTeX
\={o}
e não\=o
; com mais algumas linhas poderíamos apoiar este último também. Da mesma forma, se em vez de\c{k}
tivermos\c k
ou\c {k}
, etc. - Ignora completamente (não substitui nada) linhas que contêm
\def
ou\newcommand
; em vez disso, se quiséssemos (se o arquivo de entrada estivesse tão mal escrito!), poderíamos simplesmente pular até o final do\def
ou algo assim e processar o resto. - Supõe que (para saber quando
\o
termina uma sequência de controle como) que as “letras” sãoa-zA-Z
; você pode querer adicionar itens@
a essa lista e, na verdade, poderíamos usar a definição exata de “letra” no regime catcode ativo naquele momento - LuaTeX também fornece isso.
Observe que mesmo que você normalmente compile seu arquivo com pdfTeX ou XeTeX, você pode usar LuaTeX apenas para esta conversão e voltar a usar pdfTeX/XeTeX no arquivo convertido.