列表:持续着色的数字

列表:持续着色的数字

我一直在使用此解决方案在 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_2var3)。但上面的例子也显示了几个我无法修复的问题:

  • 可以看到,前面带有(或后面紧跟着的数字)没有颜色,例如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

为完整性起见,在 xetex 中使用 interchartoks 的非 Lua 解决方案在最后一刻失败了,因为 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}

相关内容