我正在尝试排版一些 Python 代码,并且希望突出显示整数文字。经过大约两个小时与文档和这里以及 SO 上的各种其他问题斗争后,我得出了以下结论:
\lstset{ %
language=Python,
otherkeywords={1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
morekeywords=[2]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0},
keywordstyle=[2]{\color{orange}},
keywordstyle=\color{blue}\bfseries,
stringstyle=\color{red},
}
很遗憾,这不管用。字符串中的数字也会被突出显示,这相当烦人,而且它们不仅被突出显示:它们还会在 中突出显示blue
。另一方面,常规程序文本中的数字会在 中正确突出显示red
。
帮助?
编辑:感谢 Peter Grill 提供的非常好的解决方案。但是,有没有办法不破坏字符串着色?当我使用您的代码时,它stringstyle=\color{red}
似乎不再起作用(字符串只是纯黑色)。同样,在 python 中,注释可以用三重引号括起来,如果我调整您的引号以检测"""
块,则相应的注释将不再突出显示。
答案1
看起来您想要对数字进行着色,但当它们位于字符串中时则不需要。如果我理解正确,您可以使用条件来定义我们是否应该应用颜色。然后,当我们遇到引文时,我们会禁用着色,直到遇到下一个引文。
这里我禁用了单引号和双引号内的颜色。如果不想这样,只需注释掉 中的相应行即可\lstset
。
下面我使用newtoggle
了包裹etoolbox
因为我更喜欢那个语法而不是\newif
语法。但如果你不想包含额外的包,那么调整它以使用\newif
或其他一些条件方法。
进一步增强:
如果您希望扩展它来处理浮点数,并突出显示小数分隔符(但不是句点),请参阅列表包:如何格式化所有数字?
进一步的改进是禁用代码中注释的颜色。但是,这取决于所排版的特定语言,但可以应用类似的技术来禁用注释开头的颜色,并在注释结尾重新启用它。对于具有开始和结束分隔符的注释(即
/* ... */
C 样式注释),这应该很简单,但对于行末的注释(即//
C 样式注释),需要检测行末并使用它重新启用注释。
更简单的解决方案:
- 正如 @MarkS.Everitt 在评论中指出的那样,还有一种替代解决方案:按列表包显示颜色的字符串
代码:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xcolor}
\usepackage{listings}
\newtoggle{InString}{}% Keep track of if we are within a string
\togglefalse{InString}% Assume not initally in string
\newcommand*{\ColorIfNotInString}[1]{\iftoggle{InString}{#1}{\color{red}#1}}%
\newcommand*{\ProcessQuote}[1]{#1\iftoggle{InString}{\global\togglefalse{InString}}{\global\toggletrue{InString}}}%
\lstset{literate=%
{"}{{{\ProcessQuote{"}}}}1% Disable coloring within double quotes
{'}{{{\ProcessQuote{'}}}}1% Disable coloring within single quote
{0}{{{\ColorIfNotInString{0}}}}1
{1}{{{\ColorIfNotInString{1}}}}1
{2}{{{\ColorIfNotInString{2}}}}1
{3}{{{\ColorIfNotInString{3}}}}1
{4}{{{\ColorIfNotInString{4}}}}1
{5}{{{\ColorIfNotInString{5}}}}1
{6}{{{\ColorIfNotInString{6}}}}1
{7}{{{\ColorIfNotInString{7}}}}1
{8}{{{\ColorIfNotInString{8}}}}1
{9}{{{\ColorIfNotInString{9}}}}1
}
\begin{document}
\begin{lstlisting}[basicstyle=\ttfamily]
These are colored 0123456789,
but "these are not 0123456789"
and 'these also are not 0123456789'
again colored: 0123456789
\end{lstlisting}
\end{document}
答案2
这是一种将样式应用于数字(仅限外部字符串和注释)的方法,可以改进Peter Grill 的方法两种方式。
- 它更加灵活,因为它允许你指定额外的替换(
<=
通过$\leq$
)以使其生效到处在代码中;这很方便,因为在实践中,你可能至少想要一些文学替换也出现在注释(特别是)和字符串中。 - 无论您如何定义字符串和注释分隔符,它都可以“开箱即用”,因此更加强大。
\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\newcommand\digitstyle{\color{red}}
\makeatletter
\newcommand{\ProcessDigit}[1]
{%
\ifnum\lst@mode=\lst@Pmode\relax%
{\digitstyle #1}%
\else
#1%
\fi
}
\makeatother
\lstset{literate=
{0}{{{\ProcessDigit{0}}}}1
{1}{{{\ProcessDigit{1}}}}1
{2}{{{\ProcessDigit{2}}}}1
{3}{{{\ProcessDigit{3}}}}1
{4}{{{\ProcessDigit{4}}}}1
{5}{{{\ProcessDigit{5}}}}1
{6}{{{\ProcessDigit{6}}}}1
{7}{{{\ProcessDigit{7}}}}1
{8}{{{\ProcessDigit{8}}}}1
{9}{{{\ProcessDigit{9}}}}1
{<=}{{\(\leq\)}}1,
morestring=[b]",
morestring=[b]',
morecomment=[l]//,
}
\begin{document}
\begin{lstlisting}[basicstyle=\ttfamily]
These are colored 0123456789,
but "these are not 0123456789"
and 'these also are not 0123456789'
again colored: 0123456789
// not colored: 0123456789
Additional literate replacement:
<= "<=" // comment 1 <= 2
\end{lstlisting}
\end{document}