逃离地狱

逃离地狱

给定以下 MWE,其中code函数的参数包含下划线:

\documentclass [11pt,oneside,onecolumn]{article}
\usepackage{listings}
\usepackage{filecontents}

\begin{filecontents*}{hello_world.c}
#include <stdio.h>

int main(void) {
  printf("Hello World!\n");
  // return 0;
}
\end{filecontents*}


\makeatletter
\def\code{\@ifnextchar[{\@with}{\@without}}
\def\@with[#1]#2{
}
\def\@without#1{
  \section{#1}
  \lstinputlisting[]{#1}
}
\makeatother

\begin{document}
\code{hello_world.c}
\end{document}

#1两个不同的函数使用了相同的参数: section,需要对下划线进行转义;lstinputlisting,需要对下划线进行转义。不是逃脱。

如果用户对文件名进行转义,编译会因为 而失败section。如果用户不对文件名进行转义,listings则无法找到文件名。

如何解决这个问题?

答案1

请尝试使您的 MWE 独立存在(如在此答案中一样),这在回答时确实有帮助。

您可以使用 eTeX 原语\detokenize来进行_安全T1字体编码,以便_将字符打印为下划线:

\documentclass [11pt,oneside,onecolumn]{article}
\usepackage[T1]{fontenc}
\makeatletter
\usepackage{listings}

\def\code{\@ifnextchar[{\@with}{\@without}}%
\def\@with[#1]#2{%
}
\def\@without#1{%
  \section{\protect\detokenize{#1}}%
  \lstinputlisting[]{#1}%
}

\makeatother

\begin{document}

\tableofcontents

\code{hello_world.c}
\end{document}

答案2

有多个包负责排版文件名,例如 url、path。以下示例使用包 url。我假设的可选参数的\code目的是将选项传递给 lstinputlisting 命令。在这种情况下,使用 进行黑客攻击\@ifnextchar是没有必要的。

\documentclass [11pt,oneside,onecolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{listings}
\usepackage{url}
\usepackage{makerobust}

% Define \file that typeset a file name using the url package
% that also takes care of hyphenation issues, ...
\newcommand*{\file}{}% to get an error if \file is already defined
\DeclareUrlCommand{\file}{\urlstyle{sf}}
% Different styles are available, e.g.:
% sf: sans serif font (\sffamily)
% rm: roman font (\rmfamily)
% tt: typewriter font (\ttfamily)
\MakeRobustCommand{\file}
% as robust command \file do not need \protect

\newcommand*{\code}[2][]{%
  \section{\file{#2}}%
  \lstinputlisting[{#1}]{#2}%
}

\begin{document}

\tableofcontents

\code{hello_world.c}

\end{document}

相关内容