使用 listing 包对数字进行着色

使用 listing 包对数字进行着色

我正在尝试排版一些 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 样式注释),需要检测行末并使用它重新启用注释。

更简单的解决方案:

代码:

\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 的方法两种方式。

  1. 它更加灵活,因为它允许你指定额外的替换(<=通过$\leq$)以使其生效到处在代码中;这很方便,因为在实践中,你可能至少想要一些文学替换也出现在注释(特别是)和字符串中。
  2. 无论您如何定义字符串和注释分隔符,它都可以“开箱即用”,因此更加强大。

在此处输入图片描述

\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}

相关内容