
he estado usandoesta soluciónencontrado aquí en LaTeX Stack Exchange para colorear números en extractos de mi código:
\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\makeatletter
%%% Copied from https://tex.stackexchange.com/a/500690/23765
% Some conditional tests
\def\@genericif#1{#1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
\def\@ifdigit#1{\@genericif{\ifnum1<1\noexpand#1\relax}}
\def\@ifempty#1{\@genericif{\if\relax\detokenize{#1}\relax}}
% The main parsing macros
\def\parse@num#1{%
\@ifempty{#1}%
{\parse@num@false}%
{\@genericif{\parsesign}%
{\parse@num@sign#1{}\@end}%
{\parse@num@dig#1{}\@end}%
}%
}
% Parse sign
\def\parse@num@sign#1#2\@end{%
\@genericif{\ifx\parse@num@minus#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@dig#2\@end}}%
{\@genericif{\ifx\parse@num@plus#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@dig#2\@end}}%
{\parse@num@dig#1#2\@end}%
}%
}
% Parse first digit
\def\parse@num@dig#1#2\@end{%
\@ifdigit{#1}%
{\@ifempty{#2}{\parse@num@true}{\parse@num@digs#2\@end}}%
{\parse@num@false}%
}
% Parse optional following digits
\def\parse@num@digs#1#2\@end{%
\@ifdigit{#1}{%
\@ifempty{#2}%
{\parse@num@true}%
{\parse@num@digs#2\@end}%
}{%
\@genericif{\parsefloat}{%
\@genericif{\ifx\parse@num@point#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@decs#2\@end}}%
{\parse@num@false}%
}{\parse@num@false}%
}%
}
% Parse decimal places
\def\parse@num@decs#1#2\@end{%
\@ifdigit{#1}{%
\@ifempty{#2}%
{\parse@num@true}%
{\parse@num@decs#2\@end}%
}{\parse@num@false}%
}
% User interface
\newcommand\ifnumber[4][]{%
\begingroup
\let\parsesign=\iftrue
\let\parsefloat=\iftrue
\let\parse@num@minus=-%
\let\parse@num@plus=+%
\let\parse@num@point=.%
#1%
\def\parse@num@true{\endgroup#3}%
\def\parse@num@false{\endgroup#4}%
\parse@num{#2}%
}
%%% Additions to the listings package
\lst@Key{numbersstyle}{}{\def\lst@numbersstyle{#1}}
\lst@Key{parsenumbers}{false}[t]{\lstKV@SetIf{#1}\lst@ifparsenumbers}
\lst@AddToHook{OutputOther}{%
\lst@ifparsenumbers
% Only if mode changes are not prohibited
\lst@ifmode\else
\expandafter\@hook@ifnumber\the\lst@token\@end
{\let\lst@thestyle=\lst@numbersstyle}%
{}%
\fi
\fi
}
\def\@hook@ifnumber#1#2\@end{%
\@genericif{\ifx\lst@nolig#1}%
{\@hook@ifnumber@{#2}}%
{\@hook@ifnumber@{#1#2}}%
}
\def\@hook@ifnumber@{%
\ifnumber[\expandafter\let\expandafter\parse@num@minus\csname lst@um-\endcsname]%
}
\makeatother
%%% Example document
\lstset{
basicstyle = \ttfamily,
identifierstyle = \color{blue},
keywordstyle = \color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
% Apply new number coloring routine
parsenumbers = true,
numbersstyle = {\color{magenta}}
}
Funciona bastante bien pero lamentablemente también tiene algunos problemas. Adjuntando esto arriba de mi ejemplo mínimo a continuación...:
\begin{document}
\section{Python}
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\section{Processing}
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}
...da como resultado:
Los resultados no son malos y es particularmente bueno que esa solución maneje números en nombres de variables independientemente de si van seguidos de un subrayado o no (por ejemplo, var_2
y var3
). Pero el ejemplo anterior también muestra un par de problemas que no he podido solucionar:
- Es posible ver que los números precedidos por a
(
o inmediatamente seguidos por)
no están coloreados, por ejemplorange(3)
,size(300, 300)
- los números que tocan signos como comas, dos puntos o punto y coma tampoco están coloreados; por ejemplo, el número del medio en
background(0, 200, 0);
, o los números enx = x + 0.1;
oif var_2 > 1.23:
- por otro lado, tener espacios alrededor da como resultado un resaltado adecuado, por ejemplo
y = 0 ;
(con espacio antes del punto y coma) o el número1000
enelif (var3 <= 1000 and var_2 is None):
¿Alguien podría ayudarme a modificar este fragmento para que los números se resalten consistentemente en estas situaciones sin estar resaltados en los nombres de variables y funciones?
Editar: en pocas palabras, me gustaría que se resaltaran los números si:
- vienen después de cualquiera de los siguientes caracteres:
,
.
,(
,{
,[
,:
- vienen antes de cualquiera de los siguientes caracteres:
,
.
,)
,}
,]
,:
,;
- pero definitivamente no incluirlo
_
en ninguno de los grupos, ya que eso podría romper la convención de nomenclatura de variables en muchos fragmentos de código (aunque Python acepta_
números para ayudar a la identificación visual de grupos de 10^3, como enx = 1_000_000
.
Actualmente, el código anterior solo identifica correctamente y
.
de todos los caracteres mencionados en los puntos anteriores.
Editar: desafortunadamente minted
no es una opción para mí, no combina bien con mi archivo de tesis.
Respuesta1
Considere usar minted
y personalizar las hojas de estilo.
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{minted}
\usemintedstyle{colorful}
\begin{document}
\begin{minted}{python}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{minted}
\begin{minted}{c}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{minted}
\end{document}
Respuesta2
Si entendí la pregunta, desea colorear todos los dígitos a menos que estén en palabras clave o identificadores. Puede hacer esto utilizando como fuente base una fuente que tenga dígitos coloreados y una fuente diferente para las palabras clave. Con lualatex esto es posible:
\documentclass{article}
\usepackage{listings,xcolor}
\usepackage{fontspec}
\directlua{
luaotfload.add_colorscheme("colordigits",
{
["FF00FF"] = {"one","two","three","four","five","six","seven","eight","nine","zero"},
})}
\newfontfamily\colordigits{Latin Modern Mono}[RawFeature={color=colordigits}]
\lstset{
basicstyle = \colordigits,
identifierstyle = \ttfamily\color{blue},
keywordstyle = \ttfamily\color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
}
%
\begin{document}
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\section{Processing}
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}
Respuesta3
Para completar, una solución que no es Lua y utiliza interchartoks en xetex falla en el último momento porque lstlistings inserta pegamento entre los tokens. Los interchartoks consideran que el pegamento es un marcador de límites entre palabras.
Así que no es una respuesta (sin reescribir el paquete (¿usando ensambladores de ancho cero?), incluso si el escenario de pdflatex fuera superable.
Para ilustrar las transiciones entre clases de tokens:
el rojo es la transición entre el límite de la palabra y el dígito.
MWE
\documentclass{article}
\XeTeXinterchartokenstate=1
\usepackage{listings,xcolor}
\usepackage{fontspec}
\newXeTeXintercharclass\LetterClass
%from:
%https://tex.stackexchange.com/questions/411846/xelatex-minion-pro-and-italian-apostrophe-kerning/411850#411850
\makeatletter
\@tempcnta=`\A
\loop\unless\ifnum\@tempcnta>`\Z
\XeTeXcharclass \@tempcnta \LetterClass
\advance \@tempcnta by 1
\repeat
\@tempcnta=`\a
\loop\unless\ifnum\@tempcnta>`\z
\XeTeXcharclass \@tempcnta \LetterClass
\advance \@tempcnta by 1
\repeat
\XeTeXcharclass `\_ \LetterClass
\makeatother
% char class for digits
\newXeTeXintercharclass \mydigitsclass
\XeTeXcharclass `\0 \mydigitsclass
\XeTeXcharclass `\1 \mydigitsclass
\XeTeXcharclass `\2 \mydigitsclass
\XeTeXcharclass `\3 \mydigitsclass
\XeTeXcharclass `\4 \mydigitsclass
\XeTeXcharclass `\5 \mydigitsclass
\XeTeXcharclass `\6 \mydigitsclass
\XeTeXcharclass `\7 \mydigitsclass
\XeTeXcharclass `\8 \mydigitsclass
\XeTeXcharclass `\9 \mydigitsclass
% def interchartokes
\XeTeXinterchartoks \LetterClass \mydigitsclass = {\begingroup\huge}
\XeTeXinterchartoks \mydigitsclass \LetterClass = {\endgroup}
\XeTeXinterchartoks 0 \mydigitsclass = {\begingroup\color{green}}
\XeTeXinterchartoks \mydigitsclass 0 = {\endgroup}
\XeTeXinterchartoks 4095 \mydigitsclass = {\begingroup\color{red}}
\XeTeXinterchartoks \mydigitsclass 4095 = {\endgroup}
\lstset{
% basicstyle = \colordigits,
identifierstyle = \ttfamily\color{blue},
keywordstyle = \ttfamily\color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
}
\begin{document}
\XeTeXinterchartokenstate=0
\section{Test}
\XeTeXinterchartokenstate=1
abc 012 345 678 9 xyz
[The lstlisting environment adds "\textbackslash glue 0 plus 1fil minus 1fil" betweeen every token]
%https://tex.stackexchange.com/questions/281566/xetex-special-xetexcharclass-needed-for-null-glues/321664#321664
\XeTeXinterchartokenstate=0
\subsection{Inline}
\XeTeXinterchartokenstate=1
def foobar(self):
var = 123 + 456
var\_2 = 4.56
var3 = 789
for \_ in range(3):
print(test)
if var\_2 > 1.23:
print(1024)
\XeTeXinterchartokenstate=0
\subsection{Verbatim}
\XeTeXinterchartokenstate=1
\begin{verbatim}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
\end{verbatim}
\XeTeXinterchartokenstate=0
\subsection{Listing}
\XeTeXinterchartokenstate=1
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\XeTeXinterchartokenstate=0
\section{Processing}
\XeTeXinterchartokenstate=1
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}