我经常需要在幻灯片中展示 Python 代码片段,我喜欢用Python导师不幸的是,仅仅\href{my_url}{my_title}
是 是有问题的,因为 URL 会包含很多像 和 这样的字符%
,而&
这对于 LaTeX 来说是一个问题。
我当然可以逃避所有这些情况,但有没有更优雅/实用的解决方案?我知道 PythonTutor 的缩短 URL 选项可以解决这个问题,但如果我更改代码,它就不理想了;首选的选项是从某个myprogram.py
文件读取数据并使用代码生成指向 PythonTutor 的有效链接的命令。
更新
\linkmyfile{pathtofile}{mycaption}
我在准备 moewe 正确建议的示例时找到了一个修复方法:只需使框架变得脆弱即可。编译成功,链接功能齐全;但我仍然对像上面描述的命令那样运行感兴趣。
\documentclass{beamer}
\begin{document}
\begin{frame}[fragile]
\centering
\href{http://www.pythontutor.com/visualize.html#code=print%28%22Hello%20World!%22%29&cumulative=true&curInstr=0&heapPrimitives=false&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false}{\bf Visualize my code}
\end{frame}
\end{document}
答案1
自动链接到该网站的命令\pythontutorlink{filename}{label}
并不难实现。关键部分是
- 读取 Python 文件并存储结果,
- 将所有非字母和非数字字符转义为相应的
%
序列, - 最后使用 创建链接
\href
。
读取文件而不让 LaTeX 抱怨特殊字符、括号不匹配等问题,这看起来有点棘手,但使用catchfile
包却非常简单。该包已经提供了一个命令\CatchFileDef
,用于读取文件并将其内容存储在一个新宏中。在读取文件之前,我们需要确保正确处理特殊字符。这可以通过将所有特殊字符的 catcode 更改为类“other”来实现(在 中完成\@setupcatcodes
)。
现在,我们将文件内容存储在 中\@tempfile
。接下来是从中构建 URL。最终 URL 将存储在令牌寄存器中\@encodedurl
,该寄存器在实际代码部分之前预填充 URL 部分。现在,我们将文件内容中的每个字符映射到其对应的%
-sequence,如果是字母或数字,则保持不变。\@urlencode
通过遍历其参数文本并调用每个字符来完成整个替换\@encodechar
,这会将适当的结果附加到\@encodedurl
。最后,可以添加一些额外的 URL 查询参数,然后将结果传递给\href
以产生最终输出。
以下是带有示例链接的完整代码:
\documentclass{article}
\usepackage{filecontents}
\usepackage{catchfile}
\usepackage{hyperref}
\begin{filecontents*}{fibs.py}
def F(n):
if n == 0: return 0
elif n == 1: return 1
else: return F(n-1)+F(n-2)
print(F(6))
\end{filecontents*}
\makeatletter
\endlinechar=-1
\newtoks\@encodedurl
\def\@addtourl#1{\global\addto@hook\@encodedurl{#1}}
\def\@addtourlesc#1{\expandafter\@addtourl\expandafter{\@perc#1}}
{
\catcode`\#=12\relax
\catcode`\%=12\relax
\catcode`\&=12\relax
\gdef\@perc{%}
\gdef\@hash{#}
\gdef\@amp{&}
}
\def\@urlencode#1{\@@urlencode#1{}\@end}
\def\@@urlencode#1#2\@end{
\@encodechar{#1}
\if\relax\detokenize{#2}\relax
\else
\@@urlencode#2\@end
\fi
}
\def\@encodechar#1{
\ifnum`#1=`\^^M \@addtourlesc{0D}\else
\ifnum`#1=`\ \@addtourl{+}\else
\ifnum`#1=`\! \@addtourlesc{21}\else
\ifnum`#1=`\" \@addtourlesc{22}\else
\ifnum`#1=`\# \@addtourlesc{23}\else
\ifnum`#1=`\$ \@addtourlesc{24}\else
\ifnum`#1=`\% \@addtourlesc{25}\else
\ifnum`#1=`\& \@addtourlesc{26}\else
\ifnum`#1=`\' \@addtourlesc{27}\else
\ifnum`#1=`\( \@addtourlesc{28}\else
\ifnum`#1=`\) \@addtourlesc{29}\else
\ifnum`#1=`\* \@addtourlesc{2A}\else
\ifnum`#1=`\+ \@addtourlesc{2B}\else
\ifnum`#1=`\, \@addtourlesc{2C}\else
\ifnum`#1=`\- \@addtourlesc{2D}\else
\ifnum`#1=`\. \@addtourlesc{2E}\else
\ifnum`#1=`\/ \@addtourlesc{2F}\else
\ifnum`#1=`\: \@addtourlesc{3A}\else
\ifnum`#1=`\; \@addtourlesc{3B}\else
\ifnum`#1=`\< \@addtourlesc{3C}\else
\ifnum`#1=`\= \@addtourlesc{3D}\else
\ifnum`#1=`\> \@addtourlesc{3E}\else
\ifnum`#1=`\? \@addtourlesc{3F}\else
\ifnum`#1=`\@ \@addtourlesc{40}\else
\ifnum`#1=`\[ \@addtourlesc{5B}\else
\ifnum`#1=`\\ \@addtourlesc{5C}\else
\ifnum`#1=`\] \@addtourlesc{5D}\else
\ifnum`#1=`\{ \@addtourlesc{7B}\else
\ifnum`#1=`\| \@addtourlesc{7C}\else
\ifnum`#1=`\} \@addtourlesc{7D}\else
\@addtourl{#1}
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
}
\def\@setupcatcodes{
\let\do=\@makeother\dospecials
\@makeother\ \relax
\@makeother\^^M\relax
}
\def\pythontutorlink#1#2{
\begingroup
\@setupcatcodes
\CatchFileDef\@tempfile{#1}{}
\global\@encodedurl={http://www.pythontutor.com/visualize.html\@hash code=}
\expandafter\@urlencode\expandafter{\@tempfile}
\@addtourl{\@amp mode=display}
\expandafter\href\expandafter{\the\@encodedurl}{#2}
\endgroup
}
\endlinechar=`\^^M
\makeatother
\begin{document}
Example link: \pythontutorlink{fibs.py}{Fibonacci numbers}
\end{document}
如果 Python 代码中出现其他非 ASCII 字符,则可能需要添加更多字符映射。一个有趣的补充是使用类似于完全可扩展的十六进制数转换直接从字符代码计算十六进制代码,尤其是与 XeLaTeX 和 Unicode 输入一起使用时。