我最近发过这个答案到如何突出显示紧跟等号的所有形式为 [0-9][A-Za-z0-9]* 的单词?。它可以工作,但是存在(大量)代码重复的问题。
我目前拥有的
更具体地说,我必须使用以下形式
\lst@DefSaveDef{`<char>}\jubobs@<char>{\jubobs@<char>\foo}
不少于52次,用于<char>
-A
和Z
- a
。z
供参考,\lst@DefSaveDef
是一个listings
内部宏,其语法如下:
\lst@DefSaveDef{<charcode>}<some-macro>{<replacement-text>}
使用我的新认识\expandafter
,我设法通过定义一个以字母作为参数并执行与上面所示相同的操作的宏来稍微减少代码:
\makeatletter
\newcommand\addtoletterdef[1]
{%
\expandafter\expandafter\expandafter\lst@DefSaveDef%
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter`%
\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter}%
\expandafter\csname jubobs@#1\expandafter\endcsname%
\expandafter{\csname jubobs@#1\endcsname\foo}%
}
\makeatother
但是,这对减少代码重复并没有太大帮助:我仍然需要调用\addtoletterdef
52 次……;...(
我想要的是
我想定义一个类似于我的宏\addtoletterdef
,但它接受的是字符代码而不是字符。这样,就可以轻松循环遍历字符代码 65 到 90 (AZ) 和 97 到 122 (az),并执行所有这 52 个操作,而不会出现任何代码重复。
我觉得答案在于使用\begingroup\lccode
诡计但这个技巧对我来说太新了,我还远远没有掌握它。
我如何重新定义\addtoletterdef
以接受字符代码而不是字符?
梅威瑟:
\documentclass{article}
\usepackage{listings}
% dummy macro
\def\foo{foo}
\makeatletter
\newcommand\addtoletterdef[1]
{%
\expandafter\expandafter\expandafter\lst@DefSaveDef%
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter`%
\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter}%
\expandafter\csname jubobs@#1\expandafter\endcsname%
\expandafter{\csname jubobs@#1\endcsname\foo}%
}
\makeatother
\lstdefinestyle{mycode}
{
language=C,
SelectCharTable=
\addtoletterdef{A}
% ...
\addtoletterdef{Z}
\addtoletterdef{a}
% ...
\addtoletterdef{z}
}
\begin{document}
\begin{lstlisting}[style=mycode]
a1 = 6.12234Z
a2 = Z1324124
\end{lstlisting}
\end{document}
答案1
您可以\lstdefine
分部分构建,并将其添加到令牌寄存器中:
\documentclass{article}
\usepackage{xcolor}
\usepackage{textcomp}
\usepackage{listings}
\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{Numbers}}%
\fi
\fi
\global\firstchartrue%
\global\startedbyadigitfalse%
\global\precededbyequalsignfalse%
}
\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}
\newtoks\jubo@toks
\jubo@toks={
language=C,
commentstyle=\color{Comments}\slshape,
stringstyle=\color{Strings},
keywordstyle={\color{Keywords}\bfseries},
alsoletter=0123456789,
SelectCharTable=%
}
\def\add@savedef#1#2{%
\begingroup\lccode`?=#1\relax
\lowercase{\endgroup
\edef\@temp{%
\noexpand\lst@DefSaveDef{\number#1}%
\expandafter\noexpand\csname lsts@?\endcsname{%
\expandafter\noexpand\csname lsts@?\endcsname\noexpand#2}%
}}%
\jubo@toks=\expandafter{\the\expandafter\jubo@toks\@temp}%
}
\count@=`0
\loop
\add@savedef\count@\processdigit
\ifnum\count@<`9
\advance\count@\@ne
\repeat
\count@=`A
\loop
\add@savedef\count@\processletter
\ifnum\count@<`Z
\advance\count@\@ne
\repeat
\count@=`a
\loop
\add@savedef\count@\processletter
\ifnum\count@<`z
\advance\count@\@ne
\repeat
%\showthe\jubo@toks % for debugging
\begingroup\edef\x{\endgroup
\noexpand\lstdefinestyle{mycode}{\the\jubo@toks}
}\x
\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 not it's
immediately preceded by an equal sign */
return 0;
}
\end{lstlisting}
\end{document}
\jubo@toks
只是为了检查,这是第 6 步之前的值
language=C, commentstyle=\color {Comments}\slshape , stringstyle=\color {Str
ings}, keywordstyle={\color {Keywords}\bfseries }, alsoletter=0123456789, Selec
tCharTable=\lst@DefSaveDef {48}\lsts@0 {\lsts@0 \processdigit }\lst@DefSaveDef
{49}\lsts@1 {\lsts@1 \processdigit }\lst@DefSaveDef {50}\lsts@2 {\lsts@2 \proce
ssdigit }\lst@DefSaveDef {51}\lsts@3 {\lsts@3 \processdigit }\lst@DefSaveDef {5
2}\lsts@4 {\lsts@4 \processdigit }\lst@DefSaveDef {53}\lsts@5 {\lsts@5 \process
digit }\lst@DefSaveDef {54}\lsts@6 {\lsts@6 \processdigit }\lst@DefSaveDef {55}
\lsts@7 {\lsts@7 \processdigit }\lst@DefSaveDef {56}\lsts@8 {\lsts@8 \processdi
git }\lst@DefSaveDef {57}\lsts@9 {\lsts@9 \processdigit }\lst@DefSaveDef {65}\l
sts@A {\lsts@A \processletter }\lst@DefSaveDef {66}\lsts@B {\lsts@B \processlet
ter }\lst@DefSaveDef {67}\lsts@C {\lsts@C \processletter }\lst@DefSaveDef {68}\
lsts@D {\lsts@D \processletter }\lst@DefSaveDef {69}\lsts@E {\lsts@E \processle
tter }\lst@DefSaveDef {70}\lsts@F {\lsts@F \processletter }\lst@DefSaveDef {71}
\lsts@G {\lsts@G \processletter }\lst@DefSaveDef {72}\lsts@H {\lsts@H \processl
etter }\lst@DefSaveDef {73}\lsts@I {\lsts@I \processletter }\lst@DefSaveDef {74
}\lsts@J {\lsts@J \processletter }\lst@DefSaveDef {75}\lsts@K {\lsts@K \process
letter }\lst@DefSaveDef {76}\lsts@L {\lsts@L \processletter }\lst@DefSaveDef {7
7}\lsts@M {\lsts@M \processletter }\lst@DefSaveDef {78}\lsts@N {\lsts@N \proces
sletter }\lst@DefSaveDef {79}\lsts@O {\lsts@O \processletter }\lst@DefSaveDef {
80}\lsts@P {\lsts@P \processletter }\lst@DefSaveDef {81}\lsts@Q {\lsts@Q \proce
ssletter }\lst@DefSaveDef {82}\lsts@R {\lsts@R \processletter }\lst@DefSaveDef
{83}\lsts@S {\lsts@S \processletter }\lst@DefSaveDef {84}\lsts@T {\lsts@T \proc
essletter }\lst@DefSaveDef {85}\lsts@U {\lsts@U \processletter }\lst@DefSaveDef
{86}\lsts@V {\lsts@V \processletter }\lst@DefSaveDef {87}\lsts@W {\lsts@W \pro
cessletter }\lst@DefSaveDef {88}\lsts@X {\lsts@X \processletter }\lst@DefSaveDe
f {89}\lsts@Y {\lsts@Y \processletter }\lst@DefSaveDef {90}\lsts@Z {\lsts@Z \pr
ocessletter }\lst@DefSaveDef {97}\lsts@a {\lsts@a \processletter }\lst@DefSaveD
ef {98}\lsts@b {\lsts@b \processletter }\lst@DefSaveDef {99}\lsts@c {\lsts@c \p
rocessletter }\lst@DefSaveDef {100}\lsts@d {\lsts@d \processletter }\lst@DefSav
eDef {101}\lsts@e {\lsts@e \processletter }\lst@DefSaveDef {102}\lsts@f {\lsts@
f \processletter }\lst@DefSaveDef {103}\lsts@g {\lsts@g \processletter }\lst@De
fSaveDef {104}\lsts@h {\lsts@h \processletter }\lst@DefSaveDef {105}\lsts@i {\l
sts@i \processletter }\lst@DefSaveDef {106}\lsts@j {\lsts@j \processletter }\ls
t@DefSaveDef {107}\lsts@k {\lsts@k \processletter }\lst@DefSaveDef {108}\lsts@l
{\lsts@l \processletter }\lst@DefSaveDef {109}\lsts@m {\lsts@m \processletter
}\lst@DefSaveDef {110}\lsts@n {\lsts@n \processletter }\lst@DefSaveDef {111}\ls
ts@o {\lsts@o \processletter }\lst@DefSaveDef {112}\lsts@p {\lsts@p \processlet
ter }\lst@DefSaveDef {113}\lsts@q {\lsts@q \processletter }\lst@DefSaveDef {114
}\lsts@r {\lsts@r \processletter }\lst@DefSaveDef {115}\lsts@s {\lsts@s \proces
sletter }\lst@DefSaveDef {116}\lsts@t {\lsts@t \processletter }\lst@DefSaveDef
{117}\lsts@u {\lsts@u \processletter }\lst@DefSaveDef {118}\lsts@v {\lsts@v \pr
ocessletter }\lst@DefSaveDef {119}\lsts@w {\lsts@w \processletter }\lst@DefSave
Def {120}\lsts@x {\lsts@x \processletter }\lst@DefSaveDef {121}\lsts@y {\lsts@y
\processletter }\lst@DefSaveDef {122}\lsts@z {\lsts@z \processletter }.
答案2
egreg
研究中的循环绝对值得回答,但您也可以使用现有工具:
代码复制了所有设置你的意见,然后它用来\xintApplyInline
进行循环(不可扩展,它会经过这里;否则可以使用可\xintApplyUnbraced
扩展地准备全部材料,然后再将其重新注入到标记流中,但这里不需要)。
\expandafter
更新:我现在才注意到从原帖复制粘贴的内容中有一些多余的内容\addtoletterdef
。人们之所以没有注意到它们,是因为\csname
使用时宏是有意义的,\relax
因此第二级的\expandafter
无论如何都没有造成任何不良影响。(并且我还删除了一些不必要的%
)
\documentclass{article}
\usepackage{xinttools}% for expandable and non-expandable loops
\usepackage{listings}
\usepackage{xcolor}
\usepackage{textcomp}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TAKEN OVER VERBATIM https://tex.stackexchange.com/a/164297/4686
%% (and egreg's answer)
\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
\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
}
\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
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% \addtoletterdef. Some \expandafter's removed!!
\newcommand\addtoletterdef[2]
{%
\expandafter\lst@DefSaveDef
\expandafter{%
\expandafter`%
\expandafter#2%
\expandafter}%
\csname jubobs@#2\expandafter\endcsname
\expandafter{\csname jubobs@#2\endcsname #1}%
}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% USE OF \xintApplyUnbraced to loop over letters or digits
\lstdefinestyle{mycode}
{
language=C,
commentstyle=\color{Comments}\slshape,
stringstyle=\color{Strings},
keywordstyle={\color{Keywords}\bfseries},
alsoletter=0123456789,
SelectCharTable=%
\xintApplyInline{\addtoletterdef\processdigit}{0123456789}%
\xintApplyInline{\addtoletterdef\processletter}
{abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}%
}
%% this is it!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}\thispagestyle{empty}
\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 not it's
immediately preceded by an equal sign */
return 0;
}
\end{lstlisting}
\end{document}