# Highlight numbers using listings package

The problem:

Is it possible to highlight all the numbers inside a lstenvironment except the numbers in comments, strings or variable names?

Example of expected output (Python in Google Colaboratory):

What I have tried:

Using How can I change the color of digits when using the listings package? I've managed to highlight the numbers this way:

In particular, I thought I had found the solution in the listings package:

literate = [*]<replacement item>. . .<replacement item>

First note that there are no commas between the items. Each item consists of three arguments: {<replace>}{<replacement text>}{<length>}. <replace> is the original character sequence. Instead of printing these characters, we use <replacement text>, which takes the width of <length> characters in the output.

[...]

The optional star indicates that literate replacements should not be made in strings, comments, and other delimited text.

Because of using the star: \literate=* numbers inside strings and comments are not being colored, that's nice, but numbers in the name of variables are being colored. I have read a lot of answers about highlight numbers using listings but none of them satisfy my requirement.

I think it will be possible to programming that "every number inside my lstenvironment should be colored except the ones preceded by letter or not colored number", but I'm not sure, and I do not know where to start.

Possible duplicates that do not work for me:

• Not viable but useful answers

alsoletter=0123456789,
keywords={[4]@invariant,0,1,2,3,4,5,6,7,8,9},
keywordstyle={[4]\color{greenpy}}


to the definition of mypy (the lststyle I defined).

This will work only if I add manually all the numbers appearing in my code as keywords (and . in decimal numbers wouldn't be colored).

1. Gonzalo Medina's answer here: listing package: colored numbers, but not colored in variable names

Adding to lstset: literate=*{number}{{{\color{greenpy}number}}}1 and escapeinside={!!}

1. karlkoeller answer here: Listings: recognize numbers and 1e-3

2 and 3 will work only if I enclose (with some escape sign, using escapeinside) manually all the numbers appearing in my code.

I can't use neither of this solutions because I have lots of code.

• Answers that don't respond to my question.

MWE:

\documentclass{article}

\DeclareFixedFont{\ttm}{T1}{txtt}{m}{n}{10} % It will be the basic font style

\usepackage{xcolor}
\definecolor{purpy}{rgb}{0.769,0.02,0.894} % Custom highlighting colors
\definecolor{bluepy}{rgb}{0.082,0.02,1}
\definecolor{brownpy}{rgb}{0.557,0.388,0.184}
\definecolor{greenpy}{rgb}{0.118,0.553,0.388}
\definecolor{strpy}{rgb}{0.796,0.102,0.118}
\definecolor{commentpy}{rgb}{0.024,0.514,0.078}
\definecolor{Background}{rgb}{0.9,0.95,0.95}

\usepackage{listings}
\lstdefinestyle{mypy}{ %My Python style definition (based on Google Colaboratory)
language=Python,
numbers=left,
numberstyle=\footnotesize,
numbersep=1em,
xleftmargin=1em,
framextopmargin=2em,
framexbottommargin=2em,
showspaces=false,
showtabs=false,
showstringspaces=false,
columns=flexible,
keepspaces=true,
tabsize=4,
basicstyle=\ttm,
backgroundcolor=\color{Background},
keywords={as,assert,async,await,break,continue,del,elif,else,except,finally,for,from,if,import,pass,raise,return,try,while,with,yield},
keywordstyle={\ttm\color{purpy}},
keywords={[2]@invariant,False,None,True,and,class,def,global,in,is,lambda,nonlocal,not,or},
keywordstyle={[2]\ttm\color{bluepy}},
keywords={[3]@invariant,abs,all,any,ascii,bin,bool,bytearray,bytes,callable,chr,classmethod,compile,complex,delattr,dict,dir,divmod,enumerate,eval,exec,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,isinstance,issubclass,iter,len,list,locals,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,range,repr,reversed,roundset,setattr,slice,sorted,@staticmethod,str,sum,super,tuple,type,vars,zip, myfun}, % myfun should be brown in its definition
keywordstyle={[3]\ttm\color{brownpy}},
stringstyle=\color{strpy},
%
literate=
*{0}{{{\color{greenpy}0}}}1 % Coloring all the digits
{1}{{{\color{greenpy}1}}}1
{2}{{{\color{greenpy}2}}}1
{3}{{{\color{greenpy}3}}}1
{4}{{{\color{greenpy}4}}}1
{5}{{{\color{greenpy}5}}}1
{6}{{{\color{greenpy}6}}}1
{7}{{{\color{greenpy}7}}}1
{8}{{{\color{greenpy}8}}}1
{9}{{{\color{greenpy}9}}}1
{.0}{{{\color{greenpy}.0}}}2
{.1}{{{\color{greenpy}.1}}}2
{.2}{{{\color{greenpy}.2}}}2
{.3}{{{\color{greenpy}.3}}}2
{.4}{{{\color{greenpy}.4}}}2
{.5}{{{\color{greenpy}.5}}}2
{.6}{{{\color{greenpy}.6}}}2
{.7}{{{\color{greenpy}.7}}}2
{.8}{{{\color{greenpy}.8}}}2
{.9}{{{\color{greenpy}.9}}}2
{e+}{{{\color{greenpy}e+}}}2
{e-}{{{\color{greenpy}e-}}}2
}

% Displaying minus symbol properly
\makeatletter
\lst@CCPutMacro
\lst@ProcessOther{"2D}{\lst@ttfamily{-{}}{-}}
\@empty\z@\@empty
\makeatother

% Desired environment definition
\lstnewenvironment{python}[1][]{
\lstset{style=mypy, frame=l, numbers=none}
}{}

\begin{document}

\begin{python}
def myfun(a11,a12):
return a11-a12+15+0.35;
print("H3ll0 W0rld")
\end{python}

\end{document}


Extra question:

Is it possible to highlight every function name automatically? (But just in its definition) Every word between def and (, just like def myfun(a11,a12):

In the example above, everytime I call myfun, its name will be displayed brown, and it is supposed to be highlighted just in its definition.

• did you check tex.stackexchange.com/a/570717/2388? May 9 at 10:40
• I vote positive for your effort.... May 9 at 11:33
• @UlrikeFischer I'm compiling the document with PdfLaTeX (I'm using TeXstudio/MikTeX). It is a huge document and 1. PdfLaTeX compiles it about 3 times faster, 2. Reconvert the entire document to LuaLaTeX is not viable. May 9 at 14:09
• You can try the minted package overleaf.com/learn/latex/Code_Highlighting_with_minted May 10 at 2:50
• @AlanXiang minted needs to be run with -shell-escape, and that's a big issue. May 10 at 7:39

It is pretty clear that you cannot do this using listings alone, unless you are willing to devote a huge amount of time to it. External tools will always be helpful. If you insist on not using minted, I would say you can still benefit from Pygments. For example, you can process your Python code with the following Python script, which tries to apply different styles for numbers and function names, respectively.

from pygments.lexers.python import Python3Lexer
from pygments import highlight, lex
from pygments.token import *

py_str = r'''
def myfun(a11, a12):
return a11-a12+15+0.35
print("h3ll0 w0rld")
'''

lex_result = list(lex(py_str, Python3Lexer()))

def listing_escape(s):
return '%*{}*)'.format(s)

def number_style(s):
return listing_escape('\\StyleNumber{%s}'%s)

def function_name_style(s):
return listing_escape('\\StyleFuncName{%s}'%s)

result = ''
for item in lex_result:
if is_token_subtype(item[0], Number):
result += number_style(item[1])
elif is_token_subtype(item[0], Name.Function):
result += function_name_style(item[1])
else:
result += item[1]

print(result)


The output of the script above is:

def %*\StyleFuncName{myfun}*)(a11, a12):
return a11-a12+%*\StyleNumber{15}*)+%*\StyleNumber{0.35}*)
print("h3ll0 w0rld")


Now, you need to modify your LaTeX source code. Basically, you need to define escapeinside and style functions for numbers and function names.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listings}
\usepackage{xcolor}

\definecolor{purpy}{rgb}{0.769,0.02,0.894} % Custom highlighting colors
\definecolor{bluepy}{rgb}{0.082,0.02,1}
\definecolor{brownpy}{rgb}{0.557,0.388,0.184}
\definecolor{greenpy}{rgb}{0.118,0.553,0.388}
\definecolor{strpy}{rgb}{0.796,0.102,0.118}
\definecolor{commentpy}{rgb}{0.024,0.514,0.078}
\definecolor{Background}{rgb}{0.9,0.95,0.95}

\DeclareFixedFont{\ttm}{T1}{txtt}{m}{n}{10} % It will be the basic font style

\usepackage{listings}
\lstdefinestyle{mypy}{ %My Python style definition (based on Google Colaboratory)
language=Python,
escapeinside={\%*}{*)},
numbers=left,
numberstyle=\footnotesize,
numbersep=1em,
xleftmargin=1em,
framextopmargin=2em,
framexbottommargin=2em,
showspaces=false,
showtabs=false,
showstringspaces=false,
columns=flexible,
keepspaces=true,
tabsize=4,
basicstyle=\ttm,
backgroundcolor=\color{Background},
keywords={as,assert,async,await,break,continue,del,elif,else,except,finally,for,from,if,import,pass,raise,return,try,while,with,yield},
keywordstyle={\ttm\color{purpy}},
keywords={[2]@invariant,False,None,True,and,class,def,global,in,is,lambda,nonlocal,not,or},
keywordstyle={[2]\ttm\color{bluepy}},
keywords={[3]@invariant,abs,all,any,ascii,bin,bool,bytearray,bytes,callable,chr,classmethod,compile,complex,delattr,dict,dir,divmod,enumerate,eval,exec,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,isinstance,issubclass,iter,len,list,locals,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,range,repr,reversed,roundset,setattr,slice,sorted,@staticmethod,str,sum,super,tuple,type,vars,zip, myfun}, % myfun should be brown in its definition
keywordstyle={[3]\ttm\color{brownpy}},
stringstyle=\color{strpy},
}

% Displaying minus symbol properly
\makeatletter
\lst@CCPutMacro
\lst@ProcessOther{"2D}{\lst@ttfamily{-{}}{-}}
\@empty\z@\@empty
\makeatother

% Desired environment definition
\lstnewenvironment{python}[1][]{
\lstset{style=mypy, frame=l, numbers=none}
}{}

% number style
\newcommand{\StyleNumber}[1]{\color{cyan}\detokenize{#1}}
% function name style
\newcommand{\StyleFuncName}[1]{\color{orange}\detokenize{#1}}

\begin{document}

\begin{python}
def %*\StyleFuncName{myfun}*)(a11, a12):
return a11-a12+%*\StyleNumber{15}*)+%*\StyleNumber{0.35}*)
print("h3ll0 w0rld")
\end{python}

\end{document}


This would give you:

This is still a listing based solution, without minted and shell escape evil, yay!

• This is a nice solution, you avoided minted and shell escape but you forgot the main idea behind the environment: copy the source code straight from python to the environment, without annoying handmade edits, like add %* \Style * May 15 at 18:37
• I didn't specify that, but I think it was obvious, since I said I was not using Gonzalo Medina's and karkoeller answers since I have lots of code May 15 at 18:40