使用以下方法解决初始问题listings

使用以下方法解决初始问题listings

我用它listings来高亮显示 ruby​​ 代码。我有以下测试文档:

\documentclass{article}

\usepackage{xcolor}
\usepackage{listings}

\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{mauve}{rgb}{0.58,0,0.82}

\lstdefinestyle{Ruby} {
    aboveskip=3mm,
    belowskip=3mm,
    showstringspaces=false,
    columns=flexible,
    basicstyle={\footnotesize\ttfamily},
    numberstyle={\tiny},
    numbers=left,
    keywordstyle=\color{blue},
    commentstyle=\color{dkgreen},
    stringstyle=\color{mauve},
    breaklines=true,
    breakatwhitespace=true,
    tabsize=2, 
    sensitive = true
}

\lstset{language=Ruby}

\begin{document}

\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
  File.open(filename, 'w+') do |f|
    [...]
    # a comment
    f.puts "whatever #{some_variable} another string part"
    f.puts 'this string contains apostrophes: \'random word\''
    [...]
  end
end
\end{lstlisting}

\end{document}

看起来像这样:

示例输出

当然,#{some_variable}由于我将其设置为字符串样式,因此以紫色/淡紫色突出显示,但这并不完全正确,因为语法#{}将执行内容而不是将该块解释为字符串(仅当在内部时" ",而不是在' ',但我愿意忽略这种微妙之处)。

我的问题是,有没有办法配置突出显示以正确表示这一点,以便#{some_variable}具有默认颜色?

编辑:根据 SDF 给出的答案,它现在看起来像这样:

稍微错误的解决方案

如果比较这两张图片,您会发现现在周围的转义撇号random word不会像以前那样被忽略(这是正确的行为)。

编辑 2:虽然我可以通过省略来解决这个问题string=[d]{'},,但我注意到另外两个问题。示例现在如下所示:

\documentclass{article}

\usepackage{xcolor}
\usepackage[procnames]{listings}

\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\definecolor{light-gray}{gray}{0.25}

\lstdefinestyle{Ruby} {
    aboveskip=3mm,
    belowskip=3mm,
    showstringspaces=false,
    columns=flexible,
    basicstyle={\footnotesize\ttfamily},
    numberstyle={\tiny},
    numbers=left,
    keywordstyle=\color{blue},
    commentstyle=\color{dkgreen},
    stringstyle=\color{mauve},
    breaklines=true,
    breakatwhitespace=true,
    tabsize=2, 
    sensitive = true,
    morestring=*[d]{"},
    morestring=[s][]{\#\{}{\}},
    procnamekeys={def},
    procnamestyle=\color{red},
}

\lstset{language=Ruby}

\begin{document}

\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
  File.open(filename, 'w+') do |f|
    [...]
    # a comment
    f.puts "whatever #{some_variable} another string part"
    f.puts 'this string contains apostrophes: \'random word\''
    f.puts 'i do love keywords like class'
    f.puts "i do love keywords like class"
    f.puts "now single quotes 'inside #{double quotes}'"
    [...]
  end
end
\end{lstlisting}

\end{document}

错误的关键字突出显示和嵌套引用问题

双引号内的关键字现在被突出显示,并且双引号内的单引号也导致原始问题再次出现。

这件事慢慢地变得无法控制了...也许我真的应该改用 minted。

答案1

笔记: 我更新了整个答案以考虑这两项修改。有很多小技巧,但我担心我们想要使用的越精确listings,我们需要添加的技巧就越多。请参阅答案末尾的替代解决方案minted

使用以下方法解决初始问题listings

您可以通过在其定义中listings添加来检测另一个分隔符内的分隔符:*

morestring=*[d]{"}

然后我们定义#{}作为特殊分隔符。我们通过添加第二对方括号赋予它们自己的样式:

morestring=[s][]{\#\{}{\}}

这里我们添加了空括号,这意味着将使用默认样式。另外,不要忘记转义特殊字符,例如#{等。有关更详细的解释,请参阅listings文档第 3.3 节。

评论: s选项意味着开始和结束分隔符不同,d它们是相同的。必须使用b而不是d启用反斜杠转义。我在最初的回答中犯了这个错误。还值得注意的是,Ruby 与大多数语言一样,已经有一个基本定义,其中包括大多数字符串,因此无需重新定义所有内容(除非我们想覆盖它,我们会这样做)。

这是\lstset产生 OP 第一次编辑中所见的输出:

\lstdefinestyle{Ruby} {
    aboveskip=3mm,
    belowskip=3mm,
    showstringspaces=false,
    columns=flexible,
    basicstyle={\footnotesize\ttfamily},
    numberstyle={\tiny},
    numbers=left,
    keywordstyle=\color{blue},
    commentstyle=\color{dkgreen},
    stringstyle=\color{mauve},
    breaklines=true,
    breakatwhitespace=true,
    tabsize=2, 
    morestring=[d]{'}, % wrong: should be [b]
    morestring=*[d]{"},
    morestring=[s][]{\#\{}{\}},
}

解决其他问题

字符串内的关键字被突出显示

正如 Daniel 在评论中所说,中的星星morestring=*[d]{"}使它能够进一步寻找更多的琴弦关键字。这就是我们想要的关于“ #{-}字符串”的内容,但它也发生在关键字上。 listings不允许指定我们在字符串中究竟要寻找什么,所以我们必须找到另一种解决方法。

现在,listings提供一个**选项,以便字符串的样式及其特殊内容可以累积。例如,当我们这样做时:

morestring=**[d][\color{mauve}]{"},
keywordstyle=\bfseries,

listings将使双引号内的关键字都变为粗体淡紫色。问题是,我们需要“累积”颜色。

morestring=**[d][\color{mauve}]{"},
keywordstyle=\color{blue},

在这种情况下,字符串内的关键字将使用 进行处理\color{mauve} \color{blue},这很糟糕:关键字样式会覆盖字符串样式。我的窍门是用一个新命令替换关键字样式,该命令检查当前颜色,如果颜色不是淡紫色,则将其设置为蓝色:

\def\bluecolorifnotalreadymauve{%
    \extractcolorspec{.}\currentcolor
    \extractcolorspec{mauve}\stringcolor
    \ifx\currentcolor\stringcolor\else
        \color{blue}%
    \fi
}

(谢谢这个答案寻找解决方案。

现在我们也失去了原来的修复,因为它的(空)样式与from#{}一起“累积” 。让我们把它累积回来:\color{mauve}""

morestring=[s][\color{black}]{\#\{}{\}},

单引号导致#{}问题再次出现

就像关键字一样,单引号字符串在双引号字符串内重新处理。并且listings没有被告知要查看单引号字符串内部,所以我们必须以相同的方式更改它们:

morestring=**[d]{'},

现在我们失去了反斜杠转义。由于未知原因,b选项与 配合不好**。好吧,既然我们这样做了……

morestring=[d]{\\'},

完全更新的 MWE

\documentclass{article}

\usepackage{xcolor}
\usepackage[procnames]{listings}

\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\definecolor{light-gray}{gray}{0.25}

\def\bluecolorifnotalreadymauve{%
    \extractcolorspec{.}\currentcolor
    \extractcolorspec{mauve}\stringcolor
    \ifx\currentcolor\stringcolor\else
        \color{blue}%
    \fi
}

\lstdefinestyle{Ruby} {
    aboveskip=3mm,
    belowskip=3mm,
    showstringspaces=false,
    columns=flexible,
    basicstyle=\footnotesize\ttfamily,
    numberstyle=\tiny,
    numbers=left,
    keywordstyle=\bluecolorifnotalreadymauve,
    commentstyle=\color{dkgreen},
    stringstyle=\color{mauve},
    breaklines=true,
    breakatwhitespace=true,
    tabsize=2,
    moredelim=[s][\color{black}]{\#\{}{\}}, % same as morestring in this case
    morestring=**[d]{'},
    morestring=[d]{\\'},
    morestring=**[d]{"},
    procnamekeys={def}, % bonus, for function names
    procnamestyle=\color{red},
}

\lstset{language=Ruby}

\begin{document}

\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
  File.open(filename, 'w+') do |f|
    [...]
    # a comment
    f.puts "whatever #{some_variable} another string part"
    f.puts 'this string contains apostrophes: \'random word\''
    f.puts 'i do love keywords like class'
    f.puts "i do love keywords like class"
    f.puts "now single quotes 'inside #{double quotes}'"
    [...]
  end
end
\end{lstlisting}

\end{document}

输出:

更新了 Ruby 代码并附上清单

替代方法:使用minted

minted已经满足了你的所有要求,甚至更多!以下是 MWE:

\documentclass{article}

\usepackage{minted}

\begin{document}

\begin{listing}[H]
  \begin{minted}[fontsize=\footnotesize, linenos]{Ruby}
  def some_function
    File.open(filename, 'w+') do |f|
      [...]
      # a comment
      f.puts "whatever #{some_variable} another string part"
      f.puts 'this string contains apostrophes: \'random word\''
      f.puts 'i do love keywords like class'
      f.puts "i do love keywords like class"
      f.puts "now single quotes 'inside #{double quotes}'"
      [...]
    end
  end
  \end{minted}
  \caption{...}
\end{listing}

\end{document}

这是具有默认样式的输出:

使用 minted 更新 Ruby 代码

的主要缺点minted是它依赖于皮格门特斯进行处理,这意味着:

  1. 安装可能有点棘手。

  2. 它很难定制。(但是一旦我们知道如何定制,它就会变得非常强大。)

相关内容