这个问题的灵感来自马丁·施罗德对我是 TeX 新手。我应该使用 LaTeX、XeLaTeX 等吗?以及我之前在这个论坛上提出的两个问题:
回想起来,我真的很惊讶没有 LuaTeX 用户回答我的问题,因为在我看来,通过在 LuaTeX 中将 Lua 脚本嵌入到 LaTeX 代码中,这很容易实现。这真的可以做到吗(仅针对 LuaTeX 用户的问题)?这容易吗?
我的第二个问题是由于,如果我已经了解 Python(如果你愿意,你可以用 Perl 代替)只是为了使用 TeX,我非常讨厌学习另一种脚本/通用编程语言(Lua)。是否有人为 TeX 制作 Python 接口,简称为 PythonTeX(PerlTeX 确实存在)?据我所知,PythonTeX 并不存在。有一种叫做PyTeX但它看起来只是一个为那些想使用 Python 语法输入 TeX 文档的人准备的工具。
与 Python 相比,使用 Lua 作为 TeX 的嵌入式脚本语言是否有优势(除了开始使用 LuaTeX 的人可能更熟悉 Lua 这一事实之外)?
答案1
LuaTeX 的开发人员在他们的主页。
嵌入解释器是一回事,而且对于 Python 来说显然没什么意思。另一件事是让 TeX 的内部结构对嵌入解释器可见。虽然很多通信代码可能以某种方式从 LuaTeX 改编为 PythonTeX,但这仍然需要大量工作。
更好的方法可能是稍微作弊,简单地搭载 LuaTeX 解释器。有一个名为“嵌入”Python 的 Lua 桥疯狂蟒蛇,也许还可以让它与 LuaTeX 配合使用。但是,使用 XML-RPC 可能更简单:让 LuaTeX 生成一个 Python 进程,充当 XML-RPC 服务器。然后 LuaTeX 命令可以调用 Python 进程。附加功能:一旦在 LuaTeX 端实现此功能,它就可以与任何其他脚本语言一起使用,而不仅仅是 Python。
答案2
我从去年 5 月开始编写“PythonTeX”,计划在下周末到 3 月初之间发布第一个公开版本。我实际上打算将其命名为 PythonTeX,类似于 PerlTeX 和 SageTeX。
我创建了一个 LaTeX 包和随附的 Python 脚本,它们提供了 python.sty、SageTeX 和 SympyTeX 的大部分功能,但更注重速度和可用性。以下是 PythonTeX 将带来什么的简要概述。
命令和环境之间的持久性。例如,每个环境
\begin{pythoncode} ... \end{pythoncode}
都会从上一个中断的地方继续,因此所有变量、函数等都会保留下来。您可以选择命名命令和环境,然后只有同名的命令和环境之间才会保留。例如,\begin{pythoncode}[name] ... \end{pythoncode}
只与名为 的其他命令和环境共享持久性name
。自动包含印刷内容。例如,
\begin{pythoncode} print(1+1) \end{pythoncode}
2
在编译后的文档中会自动替换为。速度。使用 Python 的多处理包,每组命名的命令和环境都在其自己的进程中执行。此外,每组都经过哈希处理,因此代码仅在更改时才执行。运行代码的结果会被保存,并在未检测到更改时重新使用。
代码排版。所有执行的代码都可以使用 fancyvrb 及其内部函数进行排版。也可以选择使用 Pygments 排版代码,Pygments 是一个可以进行语法高亮的 Python 包(minted 包使用 Pygments)。使用 Pygments 时,所有代码都会被散列,排版结果也会保存,因此在后续运行中,只有更改的代码才需要由 Pygments 处理。这有助于防止 Pygments 减慢速度。
有意义的错误消息。所有错误消息都由代码解析,该代码确定发生错误的文档行(而不是实际执行的 *.py 文件的行)。因此,您可以准确地知道文档中哪里出了问题。
最少文件。代码会自行清理,因此 Python 创建的永久文件数量将保持在最低限度,并且每次运行后都会删除所有临时文件。
PythonTeX 发布后我就可以发布链接。我还将在首次公开发布后不久将其提交给 CTAN。
答案3
以下是通过 JSON-RPC 从 LuaTeX 调用持久 Python 进程的一种方法。1)
所需设置:
下载并安装jsonrpclib. 这提供了 Python 服务器。
下载 Lua json-rpc 客户端。我改编了在网上找到的一些 Lua 模块,然后将它们压缩并放在我的服务器. 解压到此答案中指定的目录之一: “Lua 树”(texmf 树的类似物)
现在,我们可以编写一个公开一些功能的 Python 服务器:
import sys
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
server = SimpleJSONRPCServer(('localhost', 8080))
server.register_function(lambda: "Hello from Python!", 'ping')
server.register_function(lambda *args: sum(args), 'add')
# the counter generator shows that the server can be used
# to preserve state between requests, and even across multiple
# LaTeX compiler runs (which we may not want)
counter = iter(xrange(sys.maxint))
server.register_function(lambda: counter.next(), 'count')
server.serve_forever()
将其保存为testserver.py
并运行。
以下是展示如何调用服务器的测试文档:
\documentclass{article}
\directlua{ % make the running python server available as a proxy
require "jsonrpc"
pythonserver = jsonrpc.proxy("http://localhost:8080")
}
\newcommand{\python}[2][]{\directlua{%
result = pythonserver.#2(#1)
tex.print(result)
}}
\begin{document}
\python{ping}
The sum of 1,2,3,4,5,6,2,4,5,6 is \python[1,2,3,4,5,6,2,4,5,6]{add}
\directlua{%
for x=0,100,1 do
result = pythonserver.count()
tex.print(result)
end
}
\end{document}
回答关于如何实现 pythontex 的原始问题,现在所需的只是一个 shell 脚本,该脚本首先启动服务器,然后调用 LuaTeX,然后再次关闭服务器。这留给读者练习 ;)
1) 我之所以使用 JSON-RPC 而不是 XML-RPC,是因为我找不到只支持 Lua 的 XML-RPC 客户端;我找到的那个客户端使用 C 扩展库,而我却不知道如何将其加载到 LuaTeX 中(脸红)。JSON-RPC 模块更简单,经过一番努力(就我而言)后,我终于说服它合作了。也许有一天我也能弄清楚如何让 XML-RPC 也能工作。
答案4
实际上,将 Python 代码转换为(纯)TeX 代码的一个好方法是:
- 对于排版工作(方框、粘连和惩罚),仅使用 TeX;
- 对于计算、数据库接口等,您可以构建 Python 模块,然后通过 TeX 程序调用这些模块
\write18
。Python 模块必须将输出保留到文件中,然后通过常规方式读取这些文件\newread
,然后将其用于 TeX 代码。此解决方案在 Linux 上效果最佳,因为 Linux 上原生安装了 Python。
作为示例,尝试以下操作:按如下方式准备模块“adder.py”:
#!/usr/bin/env python
# file 'adder.py'
import sys
def save(data):
tempFile = open("temp.dat","w")
tempFile.write(str(data))
tempFile.close()
def double(x):
result = x * 2
save(result)
if __name__ == "__main__":
n = int(sys.argv[1])
double(n)
sys.exit
现在,在同一个目录中,您可以输入这样的 TeX 文件:
% file `doubler.tex'
\newread\tempfile
%
\def\double#1{%
\immediate\write18{python adder.py #1}\relax
\immediate\openin\tempfile=temp.dat
\read\tempfile to \var
\var}%
%
Double 2 is \double2\par
Double 3 is \double3\par
Double 4 is \double4\par
Double 5 is \double5\par
Double 6 is \double6\par
\bye
这个 TeX 文件必须用 shell-escape 进行编译,例如:
tex -shell-escape doubler
pdftex -shell-escape doubler
xetex -shell-escape doubler