
Ich verwendediese Lösunghier bei LaTeX Stack Exchange zum Einfärben von Zahlen in meinen Codeauszügen gefunden:
\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}}
}
Es funktioniert ziemlich gut, hat aber leider auch einige Probleme. Ich füge dies meinem Minimalbeispiel unten hinzu ...:
\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}
...führt zu:
Die Ergebnisse sind nicht schlecht, und es ist besonders gut, dass diese Lösung Zahlen in Variablennamen unabhängig davon verarbeitet, ob ihnen ein Unterstrich folgt oder nicht (z. B. var_2
und var3
). Das obige Beispiel zeigt jedoch auch einige Probleme, die ich nicht beheben konnte:
- Es ist möglich, dass Zahlen, denen ein vorangestellt ist
(
oder die unmittelbar darauf folgen,)
nicht gefärbt sind, z. B.range(3)
,size(300, 300)
- Zahlen, die Zeichen wie Kommas, Doppelpunkte oder Semikolons berühren, werden ebenfalls nicht eingefärbt; z. B. die mittlere Zahl in
background(0, 200, 0);
oder die Zahlen inx = x + 0.1;
oderif var_2 > 1.23:
- Andererseits führen Leerzeichen um sie herum zu einer korrekten Hervorhebung, z. B.
y = 0 ;
(mit Leerzeichen vor Semikolon) oder die Zahl1000
inelif (var3 <= 1000 and var_2 is None):
Kann mir jemand helfen, diesen Codeausschnitt so zu optimieren, dass die Zahlen in diesen Situationen durchgängig hervorgehoben werden, in Variablen- und Funktionsnamen jedoch weiterhin nicht?
Bearbeiten: Kurz gesagt, ich möchte, dass Zahlen hervorgehoben werden, wenn:
- Sie stehen nach einem der folgenden Zeichen:
,
.
,(
,{
,[
,:
- Sie stehen vor einem der folgenden Zeichen:
,
.
,)
,}
,]
,:
,;
- aber auf keinen Fall
_
in eine der Gruppen aufnehmen, da dies in vielen Codeausschnitten gegen die Konvention zum Benennen von Variablen verstoßen könnte (obwohl Python_
Zahlen akzeptiert, um die visuelle Identifizierung von Gruppen von 10^3 zu erleichtern, wie in )x = 1_000_000
.
Derzeit identifiziert der obige Code nur alle in den Aufzählungspunkten oben genannten Zeichen korrekt .
.
Edit: minted
ist für mich leider keine Option, da es mit meiner Dissertationsdatei nicht gut funktioniert.
Antwort1
Erwägen Sie die Verwendung minted
und Anpassung der Stylesheets.
\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}
Antwort2
Wenn ich die Frage richtig verstanden habe, möchten Sie alle Ziffern einfärben, es sei denn, sie sind in Schlüsselwörtern oder Kennungen enthalten. Sie können dies tun, indem Sie als Basisschriftart eine Schriftart verwenden, die farbige Ziffern hat, und eine andere Schriftart für die Schlüsselwörter. Mit lualatex ist dies hier möglich:
\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}
Antwort3
Der Vollständigkeit halber sei erwähnt, dass eine Nicht-Lua-Lösung mit Interchartoks in xetex im letzten Moment fehlschlägt, da lstlistings zwischen den Tokens Kleber einfügt. Kleber wird von Interchartoks als Markierung zwischen Wortgrenzen betrachtet.
Also keine Antwort (ohne eine Neufassung des Pakets (unter Verwendung von Joinern mit Nullbreite?), selbst wenn das PDFLatex-Szenario überwindbar wäre.
Um die Übergänge zwischen Token-Klassen zu veranschaulichen:
Rot ist der Übergang von der Wortgrenze zur Ziffer.
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}