这是我的代码:
\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\lstset{
basicstyle=\ttfamily,
moredelim=*[s][\color{gray}]{[}{]},
keywords=[0]{a,b,foo,baz},
keywords=[1]{Apple,Ball,bar,qux},
keywordstyle=[0]\color{blue},
keywordstyle=[1]\color{red},
}
\begin{document}
\begin{lstlisting}
[ a = Apple ]
[ b = Ball ]
[ foo = bar ]
[ baz = qux ]
Other text is rendered in basic style.
\end{lstlisting}
\end{document}
输出如下:
上面的输出是所需的输出。但上面的 LaTeX 代码不是所需的代码。我希望 LaTeX 代码能够处理任意键名和值名。键名和值名不能在 LaTeX 代码中硬编码。
顺便说一句,如果这很重要的话,在我的语法中,关键名称是关键词并且值名称是字符串。如果解决方案可以将键名解析为关键字,将值名解析为字符串并相应地设置样式,那就太好了,但不是必需的。
答案1
使用版本listings
以下是利用该功能获得所需效果的解决方案。为此,分别定义了literate
字符[
、=
和的三个钩子。]
每当[
文本中出现 a 时,方括号将设置为括号颜色,其余文本将切换到关键颜色。字符也会发生类似情况=
,但后面的文本将设置为值部分的颜色。最后,每当]
出现 a 时,我们将切换回其他颜色。
由于值部分可能会出现额外的平衡方括号,因此这里也使用了上一个解决方案中使用的括号计数(见下文)。为了检查我们当前是否处于值部分,\ifinvaluepart
引入了一个新的条件开关。
新版本的示例代码:
\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\definecolor{brackets}{named}{gray}
\definecolor{keys}{named}{blue}
\definecolor{values}{named}{red}
\definecolor{other}{named}{black}
\makeatletter
\lstset{
basicstyle={\global\invaluepartfalse
\global\@brack@level=0
\ttfamily\color{other}},
literate={[}{{\@open@bracket}}1 {=}{{\@equal@sign}}1 {]}{{\@close@bracket}}1
}
\newcount\@brack@level
\newif\ifinvaluepart
\def\@open@bracket{%
\ifinvaluepart
\global\advance\@brack@level 1
[%
\else
\textcolor{brackets}{[}%
\color{keys}%
\fi
}
\def\@equal@sign{%
\ifinvaluepart
=%
\else
\global\invalueparttrue
\textcolor{brackets}{=}%
\color{values}%
\fi
}
\def\@close@bracket{%
\ifinvaluepart
\ifnum\@brack@level>0
\global\advance\@brack@level -1
]%
\else
\global\invaluepartfalse
\textcolor{brackets}{]}%
\color{other}%
\fi
\else
]%
\fi
}
\makeatother
\begin{document}
\begin{lstlisting}
[ a = Apple ]
[ b = Ball ]
[ foo = bar ]
[ baz = qux ]
[ 'foobar' = "#" + val[x[i][j]] ]
[ \LaTeX = \textbf{cool} ]
Other text is rendered in basic style.
\end{lstlisting}
\end{document}
替代版本使用alltt
这并非您所要求的,但无论如何,它也许对您有用。listings
我们使用该alltt
包来排版代码。这使得解析键/值对变得更容易(或完全可能)。
首先,我们基于定义一个新环境kvcolor
(实际上\kvcolor
也是唯一一个) 。此外,将字符设为活动字符,并定义一个新命令,该命令使用 TeX 的分隔参数扫描第一个字符之后的所有内容,将中间的文本设置为关键字,然后将控制权移交给以解析值部分。\endkvcolor
alltt
[
[
=
\@find@string@end
我们也可以使用分隔参数作为值,但您注意到值应该是字符串类型,因此最好它们也可以包含方括号。为此,\@find@string@end
逐个字符进行扫描,从而计算平衡的[
/]
对,直到找到最后一个]
。在两者之间找到的所有内容都被视为值字符串的一部分。
这种方法相对简单,但有几个缺点。最明显的是,包提供的所有花哨功能都不listings
可用。此外,环境保留了、和字符alltt
的通常含义。如果您在其他文本中需要它们,则必须明确转义它们。另一方面,当值字符串的扫描处于活动状态时,这些字符将变为可打印字符,否则如果在值字符串中使用带参数的宏,它将严重中断。如上所述,方括号也必须匹配。\
{
}
完整代码如下:
\documentclass{article}
\usepackage{xcolor}
\usepackage{alltt}
\definecolor{brackets}{named}{gray}
\definecolor{keys}{named}{blue}
\definecolor{values}{named}{red}
\definecolor{other}{named}{black}
\makeatletter
\newcount\@brack@level
\begingroup
\catcode`\[=\active
\gdef\kvcolor{%
\alltt
\color{other}
\catcode`\[=\active
\def[##1={%
\global\@brack@level=0
\begingroup
\color{brackets}%
\char`\[%
\textcolor{keys}{##1}%
\char`\=%
\bgroup
\catcode`\[=12 \catcode`\\=12
\catcode`\{=12 \catcode`\}=12
\color{values}
\@find@string@end
}
}
\endgroup
\def\@find@string@end#1{%
\let\@next=\@find@string@end
\if\noexpand#1[%
\global\advance\@brack@level 1
\char`\[%
\else \if\noexpand#1]%
\ifnum\@brack@level>0
\global\advance\@brack@level -1
\char`\]%
\else
\let\@next=\@string@finish
\fi
\else
#1%
\fi\fi
\@next
}
\def\@string@finish{%
\egroup % \color
\char`\]%
\endgroup
}
\let\endkvcolor=\endalltt
\makeatother
\begin{document}
\begin{kvcolor}
[ a = Apple ]
[ b = Ball ]
[ foo = bar ]
[ baz = qux ]
[ 'foobar' = "#" + val[x[i][j]] ]
[ \LaTeX = \textbf{cool} ]
Other text is rendered in basic style.
\end{kvcolor}
\end{document}