列表:仅包含关键字的彩色数字

列表:仅包含关键字的彩色数字

有了该listings软件包,我想将整数从字符串、注释和关键字中着色。为数字着色的问题 到过 一些 。有些答案处理注释、字符串或裸词中出现的数字,但当关键字包含数字时,没有给出解决方案。这很烦人,因为 C 和 C++ 有很多类型包含数字,例如uint32_t

这是一个小例子。

\documentclass{standalone}
\usepackage{xcolor}
\usepackage{listings}

\definecolor{darkgreen}{rgb}{0.18,0.54,0.34}
\definecolor{maroon}{rgb}{0.64,0.16,0.16}
\definecolor{darkpink}{rgb}{0.75,0.25,0.5}

\lstdefinestyle{myc++}{
    language=[ISO]C++,
    keywordstyle=\color{darkgreen}\bfseries,
    commentstyle=\color{blue}\textit,
    stringstyle=\color{darkpink}\ttfamily,
%
    literate=*
    {0}{{{\textcolor{red}0}}}1
    {1}{{{\textcolor{red}1}}}1
    {2}{{{\textcolor{red}2}}}1
    {3}{{{\textcolor{red}3}}}1
    {4}{{{\textcolor{red}4}}}1
    {5}{{{\textcolor{red}5}}}1
    {6}{{{\textcolor{red}6}}}1
    {7}{{{\textcolor{red}7}}}1
    {8}{{{\textcolor{red}8}}}1
    {9}{{{\textcolor{red}9}}}1,
    escapeinside={|}{|},
%
    morekeywords={int32_t}
}

\begin{document}

\begin{lstlisting}[style=myc++]
// In comment: 42
int32_t in_keyword = 80085;
char *in_identifier|2| = "And in string 1337\n";
\end{lstlisting}

\end{document}

结果如下:

LaTeX 结果。

literate避免对注释或字符串内的数字进行着色的星号。escapeinside避免对有特殊标记的裸字内的数字进行着色。但我还没有找到如何int32_t对关键字进行着色的方法。

答案1

我知道这个问题已经存在三年了,但我目前正在处理同样的问题。我搜索了互联网,相同或密切相关的问题已经被问了很多次,但没有 100% 让我满意的答案,因为我正在寻找一个像这里所期望的解决方案。因为我找到了一个虽然不完美但相当不错的解决方案,我想分享它以防其他人在这里遇到。但总的来说,我同意 @Jubobs 的观点,在列表中这样做真的很麻烦。

所以基本上我所做的就是使用 basicstyle 属性将所有内容涂成我想要的数字颜色。然后我像往常一样使用 keywordstyle、commentsytle 和 stringstlye 属性为关键字、注释和字符串着色。现在的诀窍是使用 identifierstyle 为所有变量名称涂上实际的基本颜色。关于基本样式剩下的就是所有数字以及所有运算符、括号等,例如 (+ - * ... 之后,您显然只需使用基本颜色为运算符、括号等着色即可获得结果。这可以通过 literate 属性完成。

我将从我现在创建的 Julia 样式中添加几行代码来说明我的意思。请注意,在我的例子中,我想用与字符串相同的颜色来为数字着色,但显然您可以简单地为该工作创建一个新的颜色。

% julia language definition

\lstdefinelanguage{julia}{%
morekeywords=[1]{end,export,finally},%
morekeywords=[2]{true,false,ARGS},%
morekeywords=[3]{ANY,AbstractArray,AbstractChannel},%
morecomment=[l]{\#},%
morecomment=[n]{\#=}{=\#},%
morestring=[b]{"},%
morestring=[m]{'},%
}[keywords,comments,strings]



% defining the colors for
\definecolor{jlbase}{HTML}{444444}                       % julia's base color
\definecolor{jlkeyword}{HTML}{444444}                    % julia's keywords
\definecolor{jlliteral}{HTML}{78A960}                    % julia's literals
\definecolor{jlbuiltin}{HTML}{397300}                    % julia's built-ins
\definecolor{jlcomment}{HTML}{888888}                    % julia's comments
\definecolor{jlstring}{HTML}{880000}                     % julia's strings



% basic font
\def\lstbasicfont{\color{jlstring}\fontfamily{pcr}\selectfont\scriptsize}

% defining the styles for
\lstset{keywordstyle={[1]\color{jlkeyword}\bfseries}}    % julia's keywords
\lstset{keywordstyle={[2]\color{jlliteral}}}             % julia's literals
\lstset{keywordstyle={[3]\color{jlbuiltin}}}             % julia's built-ins
\lstset{commentstyle={\color{jlcomment}}}                % julia's comments
\lstset{stringstyle={\color{jlstring}}}                  % julia's strings
\lstset{identifierstyle={\color{jlbase}}}        % variables


% coloring the operators with the basecolor
% and . in floating point numbers with the desired number color
\lstset{extendedchars=false}
\lstset{literate=*
{\\}{{{\color{jlbase}\textbackslash{}}}}{1} {\{}{{{\color{jlbase}\{}}}{1} {\}}{{{\color{jlbase}\}}}}{1}
{!}{{{\color{jlbase}!}}}{1} {\%}{{{\color{jlbase}\%}}}{1} {&}{{{\color{jlbase}\&}}}{1}
{(}{{{\color{jlbase}(}}}{1} {)}{{{\color{jlbase})}}}{1} {*}{{{\color{jlbase}*}}}{1}
{+}{{{\color{jlbase}+}}}{1} {,}{{{\color{jlbase},}}}{1} {-}{{{\color{jlbase}-}}}{1}
{.}{{{\color{jlbase}.}}}{1} {/}{{{\color{jlbase}/}}}{1} {:}{{{\color{jlbase}:}}}{1}
{;}{{{\color{jlbase};}}}{1} {<}{{{\color{jlbase}<}}}{1} {=}{{{\color{jlbase}=}}}{1}
{>}{{{\color{jlbase}>}}}{1} {?}{{{\color{jlbase}?}}}{1} {[}{{{\color{jlbase}[}}}{1}
{]}{{{\color{jlbase}]}}}{1} {^}{{{\color{jlbase}\^{}}}}{1} {|}{{{\color{jlbase}|}}}{1}
{~}{{{\color{jlbase}\textasciitilde{}}}}{1}
{.0}{{{\color{jlstring}.0}}}{2} {.1}{{{\color{jlstring}.1}}}{2} {.2}{{{\color{jlstring}.2}}}{2}
{.3}{{{\color{jlstring}.3}}}{2} {.4}{{{\color{jlstring}.4}}}{2} {.5}{{{\color{jlstring}.5}}}{2}
{.6}{{{\color{jlstring}.6}}}{2} {.7}{{{\color{jlstring}.7}}}{2} {.8}{{{\color{jlstring}.8}}}{2}
{.9}{{{\color{jlstring}.9}}}{2}}



% activating the julia style
\lstset{language=julia}

好的,我猜这就是你所认为的 MWE:

\documentclass{standalone}
\usepackage{xcolor}
\usepackage{listings}

\definecolor{darkgreen}{rgb}{0.18,0.54,0.34}
\definecolor{maroon}{rgb}{0.64,0.16,0.16}
\definecolor{darkpink}{rgb}{0.75,0.25,0.5}

\lstdefinestyle{myc++}{
    language=[ISO]C++,
    keywordstyle=\color{darkgreen}\bfseries,
    commentstyle=\color{blue}\textit,
    stringstyle=\color{darkpink}\ttfamily,
    basicstyle={\color{red}},
    identifierstyle={\color{black}}, 
%
    literate=*
    {*}{{{\color{black}*}}}{1}
    {=}{{{\color{black}=}}}{1}
    {;}{{{\color{black};}}}{1}
    {.7}{{{\color{red}.7}}}{2},%
%
morekeywords={int32_t}
}

\begin{document}

\begin{lstlisting}[style=myc++]
// In comment: 42
int32_t in_keyword = 80085.7;
char *in_identifier2 = "And in string 1337\n";
\end{lstlisting}

\end{document}

结果如下:在此处输入图片描述

请注意,使用此方法您甚至不需要转义 in_identifier2 中的 2。

答案2

我认为,到目前为止,各个线程中提出的解决方案的一个缺点是它们严重依赖于该literate功能,这非常具有侵入性,可能会破坏其他代码元素的处理。因此,这里有另一种方法,虽然还远远不够完美,但可以很好地在现有的语言和样式定义之上使用。

基本思想

首先介绍一下它如何listings解析语法元素。当它尝试解析标识符时,它会寻找它认为是字符,然后是其他几个数字s。所有这些都被合并成一个标识符标记,然后进行进一步处理,例如关键字检测。每当一个数字或者其他发现不属于标识符名称的字符,它由以下所有字符组成数字其他s 合并为一个序列,然后将其作为一组字符输出。

现在我们的想法是简单地加入到这个输出过程中,并识别出所有构成合法数字文字的字符序列。只要找到这样的数字,我们就应用一种特殊的数字样式,否则我们就保持输出原样。

实施说明

对于这种非标识符序列的特殊处理,listings已经提供了一个名为的钩子OutputOther,我们将使用它来预处理这些序列(存储在中\lst@token)。

为了解析数字,我们需要一种方法,能够以不同于仅仅查找字符的方式处理至少减号-,因为listings这些是通过\lst@um-宏内部处理的。相反,宏的文字副本由这个答案提供被使用。此外,连字符的输出listings以一个宏作为前缀,该宏用于\lst@nolig防止 TeX 在连续出现多个连字符时构建连字符。对于数字,连字符/减号只能出现在数字的开头,我们只需要测试序列的第一个标记\lst@nolig并在必要时丢弃它。

其余的实现非常简单。为了便于定制,定义了两个新listings选项parsenumbers=(true|false)numbersstyle={...}(不要与已经存在的numberstyle选项混淆!)。前者启用/禁用数字解析例程,后者设置要应用的样式。我们还会在解析数字之前检查是否允许模式更改(\lst@ifmode为 false),这样数字样式就不会应用于非星号分隔符。

如下面的例子所示,这个解决方案在许多标准情况下工作得很好,但它至少在以下情况下失败了:

  • 对于像 这样的序列<identifier><plus/minus><integer>,因为listings在标识符后会中断解析,并将加号/减号和整数视为一个有符号数字。这是一个常见的词法分析问题。
  • 对于科学计数法中的浮点文字,例如0.12e3,解析过程将被视为e标识符,从而破坏整个数字组。我看不出有什么好的解决办法。作为一种解决方法,e可以将其设为数字​​字符,但这会破坏以字母 开头的标识符/关键字的解析e
  • 如果将数字用作literate字符,解析整个数字组也会失败。使用+-作为识字字符在一定程度上是可行的。

带有示例文档的代码

\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}
\begin{lstlisting}
**good cases:
   foo   foo123   _123
   123   12.345   .123
  -123  -12.345  -.123
  +123  +12.345  +.123
  +++1  1++2++3   ---1
   1-2  12 - 34    1+2

**problematic cases:
   i+1   0.1e12    i-1

**delimiters:
  / foo  123    line mode
  " foo  123 "  **delimited 
  ! foo  123 !  **inner styles
  ? foo  123 ?  **cumulative styles
\end{lstlisting}

\lstset{
    literate = {+}{{\textcolor{green}{\char`\+}}}1
               {-}{{\textcolor{red}{\char`\-}}}1
               {num}{123}3
}
\begin{lstlisting}
**literate cases:
  -123  -12.345  -.123
  +123  +12.345  +.123
  ++1+  1++2--3   --1-
   1-2  12 - 34    1+2
   num  num+num   -num
\end{lstlisting}
\end{document}

在此处输入图片描述

相关内容