
TeX 문자열이 아닌 UTF-8로 대부분의 텍스트를 처리하는 것은 많은 장점이 있습니다. 눈, 손가락 및 편집자가 쉬울 뿐만 아니라 철자법, 문법 검사기 및 기타 분석기에 텍스트를 제공하는 것도 매우 쉽습니다. .... 이 문자열을 쓴다고 상상해 보세요
ĄąĆćĘę£łŃńÓóŚś-źŻż
단순한 검색/바꾸기 전략을 사용하는 것은 다음과 같은 이유로 인해 재앙이 될 수 있습니다.
\def\L{\matbb{L}}
변환된 파일에 오류가 깊이 묻혀 있습니다. 캐릭터의 정의가 얼마나 깊이 파묻힐 수 있는지는 말할 것도 없습니다.
나는 문자를 고유하게 식별할 수 있다는 것을 이해합니다(예:여기) 그리고 그판독,tex4ht그리고하이퍼레프어느 정도 수준에서 이 문제를 처리합니다. 내 질문은: TeX 자체에서 그러한 변환기를 구현하는 것이 얼마나 실현 가능합니까?
(David가 추가함)
입력:
\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}
UTF-8 텍스트가 실행되지만 매크로 사용이 가능한 형식으로 변환됩니다.
\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}
답변1
ĄąĆćĘę£łŃńÓóŚś-źŻż
첫째, 파일 과 같은 입력을 선호하는 경우 간단히 입력(또는 붙여넣기)할 수 있습니다. pdfTeX를 사용하는 경우 또는 유니코드 인식 엔진(XeTeX 또는 LuaTeX)을 사용하는 경우에는 .tex
필요하지 않습니다. \usepackage[utf8]{inputenc}
). 예를 들어, 다음은 작동합니다( 로 컴파일할 때 xelatex
).
\documentclass{article}
\begin{document}
ĄąĆćĘę£łŃńÓóŚś-źŻż
\end{document}
문제가 입력하기에 편리한(또는 기억에 남는) 키보드 레이아웃이 없어서 TeX 매크로를 사용하여 입력하는 것을 선호하는 것이라면(그러나 여전히 위와 같은 문자가 파일에 포함되는 것을 선호할 것입니다), 그렇다면 이것은 단순히 편집기나 입력 시스템을 설정하는 문제입니다. 예를 들어 (코멘트사용자 Loop Space), Emacs는 다음을 사용하여 이를 수행할 수 있습니다 M-x set-input-method RET TeX
. 키보드의 키를 누를 때 \=o
파일에 입력되는 내용은 입니다 ō
. Emacs를 사용할 필요는 없습니다. 이런 종류의 기능은 UIM(예).
따라서 파일을 생성하는 경우 TeX 자체를 사용하여 이러한 변환을 수행할 이유가 없습니다 .tex
. 우선 선호하는 문자를 삽입하는 방법을 찾는 것이 더 나을 것입니다.
그러나 다른 사람이 만든 파일로 작업하거나 .tex
(파일을 변경해도 괜찮음) 이 기본 설정을 지정하기 전에 직접 만든 파일로 작업하는 경우 질문이 의미가 있을 수 있습니다.
(편집기에서 간단한 검색 및 바꾸기 대신) TeX를 사용하면 매크로 정의가 like \L
및 \O
변경된 시기를 알 수 있는 기능이 제공됩니다. 이것은 또한 질문에 설명된 문제입니다.
따라서 이 문제를 해결하기 위해 내성(일명)을 사용하여 다음과 같은 솔루션이 있습니다.반사적) LuaTeX와 함께 제공되는 기능: 특히 token.get_macro
매크로의 정의를 볼 수 있게 해 주고 process_input_buffer
각 입력 줄을 검사하고 원하는 경우 변경할 수 있게 해주는 콜백을 제공합니다. 아이디어는 다음과 같습니다.
- 텍스트가 시작되기 전에 알려진 모든 문자 대체 매크로(
\L
,\"
,\c
등)의 "원래" 정의를 기록해 두십시오. 이를 통해 재정의된 시기를 알 수 있습니다. - 입력의 각 라인에 대해 해당 라인에서 발생하는 매크로를 찾으십시오.정의가 변경되지 않았는지 확인하십시오., 그리고 (그렇다면) 해당 인수와 해당 인수를 적절한 대체 항목으로 바꿉니다.
따라서 질문의 예를 사용하여 say라는 파일에서 다음을 수행합니다 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}
\directlua{dofile(...)}
( 추가된 줄 참고 ) 다음을 실행할 수 있습니다 lualatex mwe.tex
(일부 줄은 잘림).
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
그러면 다음이 포함된 파일을 찾을 수 있습니다 mwe.rewritten.tex
.
\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
여기서는 발생했어야 하는 교체만 발생한 것을 볼 수 있습니다. rewrite.lua
이를 가능하게 하는 위의 Lua 파일(위에서 호출 )은 다음과 같습니다.
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')
이는 개념 증명일 뿐이며 생산 품질 시스템이 아니기 때문에 이 접근 방식을 추구하는 데 관심이 있는 경우 작성할 수 있는 몇 가지 지름길을 선택했습니다.
- TeX의 악센트 또는 특수 문자 매크로 중 일부에 해당하는 유니코드만 나열했습니다.
- 줄 을 다시 삽입해야 합니다
\documentclass{article}
(실제로\directlua{dofile(…)}
줄 앞에 있는 모든 항목). (재미있게 선을 옮겨서 시도해 볼 수도 있습니다.~ 전에\documentclass
그리고 무슨 일이 일어나는지 보세요.) - 아마도 모든 줄 뒤에 이 줄이 있기를 원할 것입니다 .
\usepackage
어쩌면 의 시작 부분에 있을 수도 있습니다\begin{document}
. (위의 방법을 사용해보신 분이라면 그 이유를 아실 것입니다.) \relax
마지막 줄을 제거해야 합니다 . (아마도 이 줄이 나타나지 않게 할 수도 있습니다...)- 입력 파일에 LaTeX 규칙이 포함되어
\={o}
있고\=o
; 몇 줄만 더 추가하면 후자도 지원할 수 있습니다. 마찬가지로 대신에 또는 등이\c{k}
있는 경우\c k
\c {k}
\def
or 를 포함하는 행을 완전히 무시합니다(아무 것도 대체하지 않음)\newcommand
. 대신 우리가 원한다면(입력 파일이 너무 잘못 작성되었다면!) 그냥 끝까지 건너뛰고\def
나머지를 처리할 수 있습니다.- (제어 시퀀스가 언제
\o
끝나는지 알기 위해) "문자"가 다음과 같다고 가정합니다a-zA-Z
. 그 목록에 추가하고 싶을 수도 있고@
실제로 그 당시 활성화된 캣코드 체계 하에서 "문자"의 정확한 정의를 사용할 수 있습니다. LuaTeX도 이를 제공합니다.
일반적으로 pdfTeX 또는 XeTeX로 파일을 컴파일하더라도 이 변환에만 LuaTeX를 사용할 수 있으며 변환된 파일에서 다시 pdfTeX/XeTeX를 사용할 수 있습니다.