这是我的代码:
\documentclass{article}
\usepackage{listings}
\lstset{basicstyle=\ttfamily,columns=fullflexible}
\begin{document}
\lstset{escapeinside={((:}{:))}}
\begin{lstlisting}
foo
((:\textit{bar}:))
baz
\end{lstlisting}
\lstset{escapeinside={((}{))}}
\begin{lstlisting}
foo
((\textit{bar}))
baz
\end{lstlisting}
\end{document}
输出如下:
答案1
该包当然允许在 中使用多个开始和结束字符escapeinside
,因为代码会根据字符的数量(一个、两个还是两个以上)而变化。在有多个<character>
分隔符的情况下,的工作方式是使和escapeinside
中的第一个标记成为活动字符,这些活动字符会先查看并检查它们后面是否跟着定义的字符。open
close
在第一个示例中(为了简单起见,我们假设您使用了escapeinside={(:}{:)}
),(
被设为活动字符,它会向前查看并检查其后面是否跟着一个:
字符,如果是,则开始转义。在转义代码中,:
被设为活动字符并查找一个)
字符。
在第二个示例中,(
被设为活动字符,它会向前查找另一个(
,并启动转义代码。在转义代码中,)
被设为活动字符,并向前查找)
。但是它从未找到)
特点,但)
活跃角色,因此它不会结束转义代码,而只是打印 a )
。下一个)
执行相同操作并打印另一个)
1。
这个问题在您的第一个例子中没有显示出来,因为激活的字符和寻找的字符不同,所以它没有显示问题。
这里有一个建议,可以修补该问题并使其escapeinside
适用于任何字符。但要小心!我没有广泛测试此代码(阅读:除了给定的代码,我根本没有测试)所以我不知道修复此问题是否会破坏其他内容。我会说不会,因为它是一个非常具体的代码,似乎没有在其他地方使用,但警告在这里,所以你不能事后责怪我 :-)
我修改了两个定义,\lst@CDefIt
和\lst@IfNextChars@@
,分别用于两个标记分隔符和三个或更多标记分隔符。我将标记比较从更改为\ifx
,\if
这将忽略 catcode 差异,并且只比较字符本身,因此它应该可以完成您要查找的操作。我标记了更改的两行。将此代码添加到您的序言中应该可以解决问题:
\makeatletter
\def\lst@CDefIt#1#2#3#4#5#6#7#8{%
\ifx\@empty#2\@empty
\def#1{#6\def\lst@next{#7#4#8}\lst@next}%
\else \ifx\@empty#3\@empty
\def#1##1{%
#6%
% \ifx##1#2\def\lst@next{#7#4#8}\else % <--- Before
\if\noexpand##1\noexpand#2\def\lst@next{#7#4#8}\else % <--- After
\def\lst@next{#5##1}\fi
\lst@next}%
\else
\def#1{%
#6%
\lst@IfNextCharsArg{#2#3}{#7#4#8}%
{\expandafter#5\lst@eaten}}%
\fi \fi}
\def\lst@IfNextChars@@#1#2\relax#3{%
\def\lst@tofind{#2}\lst@lAddTo\lst@eaten{#3}%
% \ifx#1#3% <--- Before
\if\noexpand#1\noexpand#3% <--- After
\ifx\lst@tofind\@empty
\let\lst@next\@tempa
\else
\let\lst@next\lst@IfNextChars@
\fi
\expandafter\lst@next
\else
\expandafter\@tempb
\fi}
\makeatother
1open
如果你仔细阅读,你会发现这个解释是错误的,因为如果代码运行和close
代码失败是同一件事,那么这毫无意义。好吧,确实没有意义 :) 我猜想open
代码与close
,因此一个可以运行,另一个则不能。说实话调试listings
周日的,所以我假设部分代码有效,并且没有费力去寻找原因。