我正在使用 Latex Listings 包将代码包含在文档中。我需要实现类似于在标准 IDE 中看到的语法高亮。
我已经能够为评论、关键字和字符串分配颜色,但在弄清楚如何正确地为数字着色方面遇到了一些困难。
以下是其外观的示例:
如您所见,只要等号后面的单词以数字开头,则所有后续字符(直到(但不包括)下一个分号或空格))都会被着色。当单词以数字开头时,单词中的所有字符都应被着色,即使它们不是数字。否则,所有数字都不会被着色。
截至目前,我无法想到等号前的单词以数字开头的情况,因此找到一种为所有以数字开头的单词着色的解决方案可能是可以接受的。
在这种情况下,数字是:0-9。
这是 Latex 中的 MWE,但正如您所见,它没有任何数字的颜色。
\documentclass[pdftex]{report}
\usepackage{listings}
\usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
\definecolor{Code}{rgb}{0,0,0}
\definecolor{Keywords}{rgb}{255,0,0}
\definecolor{Strings}{rgb}{255,0,255}
\definecolor{Comments}{rgb}{0,0,255}
\definecolor{Numbers}{rgb}{255,128,0}
\lstdefinestyle{mycode}{
language=C,
% Comments
commentstyle=\color{Comments}\slshape,
% Strings
stringstyle=\color{Strings},
% keywords
keywordstyle={\color{Keywords}\bfseries}
}
\begin{document}
\begin{lstlisting}[style=mycode]
int main ()
{
//this is an example
a1 = 0;
a2 = a1;
a3 = 16hxFF;
a4 = 16 + a1;
return 0;
}
\end{lstlisting}
\end{document}
答案1
以下是改编使用 listing 包对数字进行着色:
笔记:
- 我已经使用
newtoggle
过包裹etoolbox
因为我更喜欢那个语法而不是\newif
语法。但如果你不想包含额外的包,那么调整它以使用\newif
或其他一些条件方法。
进一步增强:
- 这确实不是如果数字中有非数字,则有效。因此
16hxFF
无法正确显示,但16x
(带有尾随空格)可以。
代码:
\documentclass[pdftex]{report}
\usepackage{listings}
\usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
\definecolor{Code}{rgb}{0,0,0}
\definecolor{Keywords}{rgb}{255,0,0}
\definecolor{Strings}{rgb}{255,0,255}
\definecolor{Comments}{rgb}{0,0,255}
\definecolor{Numbers}{rgb}{255,128,0}
\usepackage{etoolbox}
\newtoggle{AfterEqualSign}% Are we supposed to be coloring digits or not
\togglefalse{AfterEqualSign}% Wait until first equal sign
\newtoggle{AlreadyColoring}% Are we already coloring digits or not
\togglefalse{AlreadyColoring}% Start off with not coloring.
\newcommand*{\ColorIfDigitsAfterEqualSign}[1]{%
\iftoggle{AfterEqualSign}{\color{orange}#1}{#1}%
\global\toggletrue{AlreadyColoring}%
}%
\newcommand*{\ColorIfAlreadyColoring}[1]{%
\iftoggle{AlreadyColoring}{%
\color{orange}#1%
}{%
\global\togglefalse{AfterEqualSign}%
#1%
}%
}%
\newcommand*{\DisableColoring}[1]{%
#1%
\global\togglefalse{AlreadyColoring}%
\global\togglefalse{AfterEqualSign}%
}%
\newcommand*{\DisableColoringIfAlreadyColoring}[1]{%
% Allows for a leading space after the =, but before the number
#1%
\iftoggle{AlreadyColoring}{%
\global\togglefalse{AfterEqualSign}%
\global\togglefalse{AlreadyColoring}%
}{}%
}%
\lstset{literate=%
{=}{{{\global\toggletrue{AfterEqualSign}{=}}}}1% Encountered equal sign
{0}{{{\ColorIfDigitsAfterEqualSign{0}}}}1
{1}{{{\ColorIfDigitsAfterEqualSign{1}}}}1
{2}{{{\ColorIfDigitsAfterEqualSign{2}}}}1
{3}{{{\ColorIfDigitsAfterEqualSign{3}}}}1
{4}{{{\ColorIfDigitsAfterEqualSign{4}}}}1
{5}{{{\ColorIfDigitsAfterEqualSign{5}}}}1
{6}{{{\ColorIfDigitsAfterEqualSign{6}}}}1
{7}{{{\ColorIfDigitsAfterEqualSign{7}}}}1
{8}{{{\ColorIfDigitsAfterEqualSign{8}}}}1
{9}{{{\ColorIfDigitsAfterEqualSign{9}}}}1
{a}{{{\ColorIfAlreadyColoring{a}}}}1
{b}{{{\ColorIfAlreadyColoring{b}}}}1
{c}{{{\ColorIfAlreadyColoring{c}}}}1
{d}{{{\ColorIfAlreadyColoring{d}}}}1
{e}{{{\ColorIfAlreadyColoring{e}}}}1
{f}{{{\ColorIfAlreadyColoring{f}}}}1
{h}{{{\ColorIfAlreadyColoring{h}}}}1% Add other characters here if needed
{A}{{{\ColorIfAlreadyColoring{A}}}}1
{B}{{{\ColorIfAlreadyColoring{B}}}}1
{C}{{{\ColorIfAlreadyColoring{C}}}}1
{D}{{{\ColorIfAlreadyColoring{D}}}}1
{E}{{{\ColorIfAlreadyColoring{E}}}}1
{F}{{{\ColorIfAlreadyColoring{F}}}}1
{\ }{{{\DisableColoringIfAlreadyColoring{\ }}}}1% Disable coloring at trailing space
{;}{{{\DisableColoring{;}}}}1% Disable coloring at semi colon
}
\lstdefinestyle{mycode} {
language=C,
% Comments
commentstyle=\color{Comments}\slshape,
% Strings
stringstyle=\color{Strings},
% keywords
keywordstyle={\color{Keywords}\bfseries}
}
\begin{document}
\begin{lstlisting}[style=mycode]
int main ()
{
//this is an example
a1 = 0;
a2 = a1;
a3 = 16hFF;
a4 = 16 + a1;
return 0;
}
\end{lstlisting}
\end{document}
答案2
回顾 Peter Grill 的方法
彼得的方法有其优点,但也存在三个局限性。
- 数字中的任何非数字都会破坏该数字的突出显示(正如 Peter 所报告的)。
- 数字在字符串中被部分突出显示,这似乎是一个错误;我猜数字在字符串中根本不应该突出显示。
listings
如果标识符包含任何需要进行文字替换的字符,则无法识别(并正确突出显示)标识符。例如,此处的return
不会被识别为关键字(因此不会以红色突出显示),因为它包含e
需要进行文字替换的字符 。
另一种方法
这是一个类似但更强大的方法,它弥补了上面讨论的所有三个限制。唯一明显的问题是代码重复。编辑: 看egreg 的回答采用更精简的方法!
\documentclass{article}
\usepackage{xcolor}
\usepackage{textcomp}
\usepackage{listings}
\definecolor{Code}{rgb}{0,0,0}
\definecolor{Keywords}{rgb}{255,0,0}
\definecolor{Strings}{rgb}{255,0,255}
\definecolor{Comments}{rgb}{0,0,255}
\definecolor{Numbers}{rgb}{255,128,0}
\makeatletter
\newif\iffirstchar\firstchartrue
\newif\ifstartedbyadigit
\newif\ifprecededbyequalsign
\newcommand\processletter
{%
\ifnum\lst@mode=\lst@Pmode%
\iffirstchar%
\global\startedbyadigitfalse%
\fi
\global\firstcharfalse%
\fi
}
\newcommand\processdigit
{%
\ifnum\lst@mode=\lst@Pmode%
\iffirstchar%
\global\startedbyadigittrue%
\fi
\global\firstcharfalse%
\fi
}
\lst@AddToHook{OutputOther}%
{%
\lst@IfLastOtherOneOf{=}
{\global\precededbyequalsigntrue}
{}%
}
\lst@AddToHook{Output}%
{%
\ifprecededbyequalsign%
\ifstartedbyadigit%
\def\lst@thestyle{\color{orange}}%
\fi
\fi
\global\firstchartrue%
\global\startedbyadigitfalse%
\global\precededbyequalsignfalse%
}
\lstdefinestyle{mycode}
{
language=C,
commentstyle=\color{Comments}\slshape,
stringstyle=\color{Strings},
keywordstyle={\color{Keywords}\bfseries},
alsoletter=0123456789,
SelectCharTable=
\lst@DefSaveDef{`0}\lsts@myzero{\lsts@myzero\processdigit}
\lst@DefSaveDef{`1}\lsts@myone{\lsts@myone\processdigit}
\lst@DefSaveDef{`2}\lsts@mytwo{\lsts@mytwo\processdigit}
\lst@DefSaveDef{`3}\lsts@mythree{\lsts@mythree\processdigit}
\lst@DefSaveDef{`4}\lsts@myfour{\lsts@myfour\processdigit}
\lst@DefSaveDef{`5}\lsts@myfive{\lsts@myfive\processdigit}
\lst@DefSaveDef{`6}\lsts@mysix{\lsts@mysix\processdigit}
\lst@DefSaveDef{`7}\lsts@myseven{\lsts@myseven\processdigit}
\lst@DefSaveDef{`8}\lsts@myeight{\lsts@myeight\processdigit}
\lst@DefSaveDef{`9}\lsts@mynine{\lsts@mynine\processdigit}
\lst@DefSaveDef{`a}\lsts@mya{\lsts@mya\processletter}
\lst@DefSaveDef{`b}\lsts@myb{\lsts@myb\processletter}
\lst@DefSaveDef{`c}\lsts@myc{\lsts@myc\processletter}
\lst@DefSaveDef{`d}\lsts@myd{\lsts@myd\processletter}
\lst@DefSaveDef{`e}\lsts@mye{\lsts@mye\processletter}
\lst@DefSaveDef{`f}\lsts@myf{\lsts@myf\processletter}
\lst@DefSaveDef{`g}\lsts@myg{\lsts@myg\processletter}
\lst@DefSaveDef{`h}\lsts@myh{\lsts@myh\processletter}
\lst@DefSaveDef{`i}\lsts@myi{\lsts@myi\processletter}
\lst@DefSaveDef{`j}\lsts@myj{\lsts@myj\processletter}
\lst@DefSaveDef{`k}\lsts@myk{\lsts@myk\processletter}
\lst@DefSaveDef{`l}\lsts@myl{\lsts@myl\processletter}
\lst@DefSaveDef{`m}\lsts@mym{\lsts@mym\processletter}
\lst@DefSaveDef{`n}\lsts@myn{\lsts@myn\processletter}
\lst@DefSaveDef{`o}\lsts@myo{\lsts@myo\processletter}
\lst@DefSaveDef{`p}\lsts@myp{\lsts@myp\processletter}
\lst@DefSaveDef{`q}\lsts@myq{\lsts@myq\processletter}
\lst@DefSaveDef{`r}\lsts@myr{\lsts@myr\processletter}
\lst@DefSaveDef{`s}\lsts@mys{\lsts@mys\processletter}
\lst@DefSaveDef{`t}\lsts@myt{\lsts@myt\processletter}
\lst@DefSaveDef{`u}\lsts@myu{\lsts@myu\processletter}
\lst@DefSaveDef{`v}\lsts@myv{\lsts@myv\processletter}
\lst@DefSaveDef{`w}\lsts@myw{\lsts@myw\processletter}
\lst@DefSaveDef{`x}\lsts@myx{\lsts@myx\processletter}
\lst@DefSaveDef{`y}\lsts@myy{\lsts@myy\processletter}
\lst@DefSaveDef{`z}\lsts@myz{\lsts@myz\processletter}
\lst@DefSaveDef{`A}\lsts@myA{\lsts@myA\processletter}
\lst@DefSaveDef{`B}\lsts@myB{\lsts@myB\processletter}
\lst@DefSaveDef{`C}\lsts@myC{\lsts@myC\processletter}
\lst@DefSaveDef{`D}\lsts@myD{\lsts@myD\processletter}
\lst@DefSaveDef{`E}\lsts@myE{\lsts@myE\processletter}
\lst@DefSaveDef{`F}\lsts@myF{\lsts@myF\processletter}
\lst@DefSaveDef{`G}\lsts@myG{\lsts@myG\processletter}
\lst@DefSaveDef{`H}\lsts@myH{\lsts@myH\processletter}
\lst@DefSaveDef{`I}\lsts@myI{\lsts@myI\processletter}
\lst@DefSaveDef{`J}\lsts@myJ{\lsts@myJ\processletter}
\lst@DefSaveDef{`K}\lsts@myK{\lsts@myK\processletter}
\lst@DefSaveDef{`L}\lsts@myL{\lsts@myL\processletter}
\lst@DefSaveDef{`M}\lsts@myM{\lsts@myM\processletter}
\lst@DefSaveDef{`N}\lsts@myN{\lsts@myN\processletter}
\lst@DefSaveDef{`O}\lsts@myO{\lsts@myO\processletter}
\lst@DefSaveDef{`P}\lsts@myP{\lsts@myP\processletter}
\lst@DefSaveDef{`Q}\lsts@myQ{\lsts@myQ\processletter}
\lst@DefSaveDef{`R}\lsts@myR{\lsts@myR\processletter}
\lst@DefSaveDef{`S}\lsts@myS{\lsts@myS\processletter}
\lst@DefSaveDef{`T}\lsts@myT{\lsts@myT\processletter}
\lst@DefSaveDef{`U}\lsts@myU{\lsts@myU\processletter}
\lst@DefSaveDef{`V}\lsts@myV{\lsts@myV\processletter}
\lst@DefSaveDef{`W}\lsts@myW{\lsts@myW\processletter}
\lst@DefSaveDef{`X}\lsts@myX{\lsts@myX\processletter}
\lst@DefSaveDef{`Y}\lsts@myY{\lsts@myY\processletter}
\lst@DefSaveDef{`Z}\lsts@myZ{\lsts@myZ\processletter}
}
\makeatother
\begin{document}
\begin{lstlisting}[style=mycode]
int main ()
{
printf("foo 3a a3")
//this is an example
a1 = 0;
a2 = a1;
a3 = 16hxFF;
a4 = 16 + a1;
// sanity check
a5 =+ 16hFF /* 16hFF is not highlighted because it's not
immediately preceded by an equal sign */
return 0;
}
\end{lstlisting}
\end{document}