Coloring digits with the listings package

It seems that you want the coloring of the digits, but not when they are within a string. If I correctly understand, you can use a conditional to define if we should apply the color or not. Then when we encounter a quote, we disable to coloring until the next quote.

Here I have disabled coloring within both single and double quotes. If this is not desired, simply comment out the corresponding line in \lstset.

enter image description here

Below I have used newtoggle from the etoolbox package as I like that syntax much better than the \newif syntax. But if you don't want to include an additional package it should be pretty straightforward to adapt this to use \newif or some other conditional methods.

Further Enhancements:

  • If you desire to extend this to handle floating point numbers, and highlight the decimal separator (but not periods), see Listings package: How can I format all numbers?

  • A further enhancement would be to disable the coloring within comments in the code. However, this is dependent on the particular language being typeset, but a similar technique could be applied to disable coloring at the beginning of a comment and re enable it at the end of the comment. This should be straightforward for comments that have a begin and end delimiter (i.e., /* ... */ C-style comments), but for comments that go to end of line (i.e., // C-style comments), the end of line will need to be detected and used to re enable comments.

Simpler Solution:

  • As @MarkS.Everitt points out in the comments, an alternative solution is available at: Colored strings by listings package

Code:

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

Here is a way of applying a style to digits (only outside strings and comments), that improves upon Peter Grill's approach in two ways.

  1. It is more flexible insofar as it allows you to specify additional replacements (of <= by $\leq$, for instance) to take effect everywhere in the code; that's handy because, in practice, you may want at least some literate replacements to also take place in comments (in particular) and in strings.
  2. It is more robust insofar as it will work "out of the box", no matter how you define your string and comment delimiters.

enter image description here

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

Tags:

Listings

Color