
Я использовалэто решениенашел здесь, на LaTeX Stack Exchange, для раскрашивания чисел в моих фрагментах кода:
\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}}
}
Он работает довольно хорошо, но, к сожалению, у него также есть некоторые проблемы. Прилагаю это выше моего минимального примера ниже...:
\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}
...результаты:
Результаты неплохие, и особенно хорошо, что это решение обрабатывает числа в именах переменных независимо от того, есть ли за ними подчеркивание или нет (например, var_2
и var3
). Но в приведенном выше примере также есть несколько проблем, которые я не смог исправить:
- Можно увидеть, что числа, которым предшествует
(
или за которыми сразу следует буква a)
, не окрашены, напримерrange(3)
,size(300, 300)
- Числа, соприкасающиеся со знаками, такими как запятые, двоеточия или точки с запятой, также не окрашиваются; например, среднее число в
background(0, 200, 0);
, или числа вx = x + 0.1;
илиif var_2 > 1.23:
- с другой стороны, наличие пробелов вокруг них приводит к правильному выделению, например
y = 0 ;
(с пробелом перед точкой с запятой) или числа1000
вelif (var3 <= 1000 and var_2 is None):
Может ли кто-нибудь помочь мне настроить этот фрагмент так, чтобы числа в этих ситуациях постоянно выделялись, но при этом не выделялись в именах переменных и функций?
Редактировать: вкратце, я бы хотел, чтобы цифры были выделены, если:
- они идут после любого из следующих символов:
,
.
,(
,{
,[
,:
- они предшествуют любому из следующих символов:
,
.
,)
,}
,]
,:
,;
- но определенно не включайте их
_
ни в одну из групп, так как это может нарушить соглашение об именовании переменных во многих фрагментах кода (хотя Python принимает_
числа, чтобы облегчить визуальную идентификацию групп по 10^3, как вx = 1_000_000
.
В настоящее время приведенный выше код правильно идентифицирует только и
.
из всех символов, упомянутых в пунктах выше.
Редактировать: к сожалению, minted
для меня это не вариант, он не согласуется с моим диссертационным файлом.
решение1
Рассмотрите возможность использования minted
и настройки таблиц стилей.
\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}
решение2
Если я правильно понял вопрос, вы хотите раскрасить все цифры, если только они не являются ключевыми словами или идентификаторами. Вы можете сделать это, используя в качестве базового шрифта шрифт с цветными цифрами и другой шрифт для ключевых слов. С lualatex это возможно:
\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}
решение3
Для полноты, не-Lua решение с использованием interchartoks в xetex терпит неудачу в последний момент, потому что lstlistings вставляет клей между токенами. Клей рассматривается interchartoks как маркер границы между словами.
Так что это не ответ (без переписывания пакета (используя соединители нулевой ширины?), даже если бы сценарий pdflatex был преодолим.
Для иллюстрации переходов между классами токенов:
красный — переход от границы слова к цифре.
МВЭ
\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}