列表:一致的著色數字

列表:一致的著色數字

我一直在使用這個解決方案在 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)。但上面的例子也顯示了一些我無法解決的問題:

  • 可以看到 a 之前(或緊接著的數字)沒有著色,例如range(3)size(300, 300)
  • 接觸逗號、冒號或分號等符號的數字也不著色;例如 中的中間數字,或或background(0, 200, 0);中的數字x = x + 0.1;if var_2 > 1.23:
  • 另一方面,它們周圍有空格會導致正確的突出顯示,例如(分號前有空格)或中的y = 0 ;數字1000elif (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 在標記之間插入了黏合。 Glue 被 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}

相關內容