内联逐字逐句,带有换行符、彩色字体和突出显示

内联逐字逐句,带有换行符、彩色字体和突出显示

我希望能够使用排队 逐字具有以下特征的文本:

  1. 换行符,例如由包spverbatim、命令提供\spverb
  2. 彩色字体,由包裹提供color
  3. 突出显示(带有彩色背景的文字),类似于soul的包\hl命令。

我所说的“内联”是指逐字部分在普通文本中(而不是具有自己段落的环境),而“逐字”是指诸如 等特殊符号\不能_被 LaTeX 解释。

我想要实现的效果是这样的(使用蓝色作为字体颜色,使用灰色作为突出显示颜色),但如果逐字部分需要换行,它应该允许换行。

在此处输入图片描述

我尝试过colornewverbsspverbatim等软件包soul,但无法将上述所有功能结合起来。我最接近的方法是:

  • 调整spverbatim的定义以spverb包含彩色字体。这样我得到了特征 1 和 2,但没有得到特征 3:

    \gdef\myVerb{%
      \bgroup
      \color{fgColor}%
      \let\spverb@ve=\verb@egroup
      \def\verb@egroup{\spverb@ve\egroup}%
      \def\@xobeysp{\mbox{}\space}%
      \verb
    }
    

    显然,\myVerb这种方式不能与soul的包链接hl使用\hl{\myVerb{verbatim text}}(LaTeX 抱怨LaTeX Error: \verb illegal in command argument.)。有什么办法可以将它们结合起来吗?例如,是否有类似于 的东西可以在上面的代码\hl后面添加以实现突出显示?\color{fgColor}

  • 使用newverbs包来定义

    \newverbcommand{\myVerb}
    {\color{fgColor}\begin{lrbox}{\verbbox}}
    {\end{lrbox}\colorbox{bgColor}{\usebox{\verbbox}}}
    

    这会使字体变色fgColor并用 突出显示bgColor,因此我得到 2 和 3;但不是 1:它不允许换行。我猜那是因为lrbox\colorbox,但我不知道如何修改它以允许换行。有什么办法吗?

  • 我当然可以使用

    \newcommand{\myVerb}[1]{{\ttfamily\color{fgcolor}{\hl{#1}}}}
    

    按照包hl进行soul操作。这样我得到了 1、2 和 3,但这不是逐字的,所以我必须转义所有特殊字符。

那么,有什么方法可以实现我想要的吗?是解决上述任何一种方法中缺少的内容,还是使用其他方法?也许有一个现成的软件包可以支持我想要的所有功能?

答案1

虽然不完全符合原作者的要求,但可能已经足够了。首先,它使用\detokenize,而不是verbatim,这意味着 1) 括号{}必须匹配,2) 符号%仍被解释为注释,3) 在所有去标记化的宏名称后插入一个空格,4) 井号的#数量加倍。

另外,我只是\allowbreak在单词之间,使用\fboxsep颜色框来创建单词间空间。

已编辑以用于\ttfamily\mytokens

\strut已编辑以修复行高,因为和的组合\fboxsep超出了允许的基线跳过预算。

最初,我没有使用单词间空格,而是允许\fboxsep就足够了。但这会导致边距问题,因为没有东西可以拉伸。因此,在重新编辑时,我在0pt minus \fboxsep单词之间插入了一个 的空格,这似乎允许足够的压缩来解决边距问题,同时仍在单词之间留出足够的空间(否则2\fboxsep)。

在重新编辑时,我还重新排列了\grayspace和,以便在尾随标点符号之前不会出现换行符。allowbreak

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\newcommand\mytokens[1]{\mytokenshelp#1 \relax\relax}
\def\mytokenshelp#1 #2\relax{\allowbreak\grayspace\tokenscolor{#1}\ifx\relax#2\else
 \mytokenshelp#2\relax\fi}
\newcommand\tokenscolor[1]{\colorbox{gray!20}{\textcolor{blue}{%
  \ttfamily\mystrut\smash{\detokenize{#1}}}}}
\def\mystrut{\rule[\dimexpr-\dp\strutbox+\fboxsep]{0pt}{%
 \dimexpr\normalbaselineskip-2\fboxsep}}
\def\grayspace{\hspace{0pt minus \fboxsep}}
\begin{document}
Here is my leading text
\mytokens{Fie Fi Fo Fum, I smell the $#@*& blood of an \Englishman.
I will continue this text to observe the margins. 
Fie Fi Fo Fum, I smell the \textbf{blood} of an Englishman.}
and my trailing text. And here is more text to find where the margin end
really should be.

Standard MATLAB formats are allowed, such as \mytokens{1.2}, \mytokens{-.2i},
\mytokens{1.}, \mytokens{-1.2e3}, \mytokens{+.2E-3j}.  \mytokens{i} and 
\mytokens{j} denote...
\end{document}

在此处输入图片描述

补充

为了响应评论请求,这里有一个将背景颜色作为可选参数的版本。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\newcommand\mytokens[2][gray!20]{\mytokenshelp{#1}#2 \relax\relax}
\def\mytokenshelp#1#2 #3\relax{\allowbreak\grayspace\tokenscolor[#1]{#2}\ifx\relax#3\else
 \mytokenshelp{#1}#3\relax\fi}
\newcommand\tokenscolor[2][gray!20]{\colorbox{#1}{\textcolor{blue}{%
  \ttfamily\mystrut\smash{\detokenize{#2}}}}}
\def\mystrut{\rule[\dimexpr-\dp\strutbox+\fboxsep]{0pt}{%
 \dimexpr\normalbaselineskip-2\fboxsep}}
\def\grayspace{\hspace{0pt minus \fboxsep}}
\begin{document}
Here is my leading text
\mytokens{Fie Fi Fo Fum, I smell the $#@*& blood of an \Englishman.
I will continue this text to observe the margins. 
Fie Fi Fo Fum, I smell the \textbf{blood} of an Englishman.}
and my trailing text. And here is more text to find where the margin end
really should be.

Standard MATLAB formats are allowed, such as \mytokens{1.2}, 
  \mytokens{-.2i}, \mytokens[red!40]{1.}, \mytokens{-1.2e3}, 
  \mytokens{+.2E-3j}.  \mytokens[cyan!30]{i} and 
  \mytokens[green!20]{j} denote...
\end{document}

在此处输入图片描述

答案2

正如我在评论中提到的那样史蒂文的回答,我最终编写了一个 Matlab 函数来转换例如

\myVerb+abc$\+

进入

\myVerb{abc\$\textbackslash }

即转义字符并用作{}分隔符。这样我就可以处理verbatim并使用

\newcommand{\myVerb}[1]{{\ttfamily\color{fgcolor}{\hl{#1}}}}

即我的问题中的第三个“解决方案”。它并不理想,但它有效;我只需要在 tex 文件上运行我的 Matlab 函数进行转换,然后再使用 LaTeX 进行编译。

这是我使用的 Matlab 函数。

function convert_myVerb(fileName)

% Converts \myVerb+...+ or \myVerb|...| into: \myVerb{...} with escaped characters

fid = fopen(fileName);
s = fread(fid);
fclose(fid);
s = char(s.');
ind = regexp(s, '(?<=\\myVerb).');
unique(s(ind)); % characters found after "\myVerb", as a check. I only used + and |
[ini, fin] = regexp(s, '\\myVerb([+|]).*?\1'); % all matching substrings
if isempty(ini)
    disp('Nothing needs to be converted. Converted file not written')
else
    disp([num2str(numel(fin)) ' substrings identified for conversion'])
    y = s(1:ini(1)-1); % output. Initiallize
    % \# \$ \% \& \textbackslash{} \textasciicircum {}\_ \{ \} \textasciitilde{}
    ini(end+1) = numel(s)+1;
    for n = 1:numel(fin)
        t = regexprep(s(ini(n)+6:fin(n)-1), '\\', '\\textbackslash '); % This has
        % to go first, so that it won't convert \ introduced to escape other
        % characters. No {} here, because they would get converted into \{\} later
        t = regexprep(t, '[#$%&_{}]', '\\$0');
        t = regexprep(t, '\^', '\\textasciicircum{}');
        t = regexprep(t, '~', '\\textasciitilde{}');
        t = ['\myVerb{' t '}'];
        y = [y t s(fin(n)+1:ini(n+1)-1)];
    end
    fid = fopen(fileName, 'w');
    count = fwrite(fid, y);
    fclose(fid);
    if count
        disp('Converted file successfully written')
    end
end

相关内容