リスト: 数字を一貫して色分けする

リスト: 数字を一貫して色分けする

私は使用していますこの解決策私のコード抜粋内の数字に色を付けるには、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。ただし、上記の例では、解決できなかった問題もいくつか示されています。

  • (が前に付いたり、直後に が付いたりする数字は)色付けされていないことがわかります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 がトークン間にグルーを挿入するため、最後の瞬間に失敗します。グルーは 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}

関連情報