
パッケージを使用して正規表現をハイライトし、通常の文字列オブジェクトのように見えるようにできるかどうか知りたいですlistings
。注: 正規表現の構文はコンテキストフリーではないため、100%のケースを認識するソリューションは期待できません。とにかく、たとえばRubyでは次のように記述したいと思います。
(/[a-z]+/)
左括弧をアンカーポイントとして使用してlistings
正規表現を認識するように指示します(算術除算とは区別するため)。/[a-z]+/
(
\lstset{moredelim=[s][\color{red}]{(/}{/}}
しかし、これにより、正規表現自体だけでなく、左括弧も色付きになります。パーサーをよりよく理解するために、ステートメントを次のように変更しました。
\lstset{moredelim=[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}}
しかし驚いたことに、「:macro:」はそれぞれトークン: 、、、、、、、、、(/
が見つかりました。私は誤って「:macro:」が[
a
-
z
]
/
moredelim
全体一致した表現(/[a-z]+/
。ちなみに、この文を二重星付きバージョンに変更すると、次のようになります。
\lstset{moredelim=**[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}}
しかし、この場合、正規表現は、式内のキーワードを色付けすることによって解析されますlistings
。これは私が望んでいることではありません。正規表現を見つけるためのアンカーとしてのみ使用し(
、その後、アンカーを正規表現自体とは別に扱いたい(別の色にする)のです。
具体的には、 -moredelim
を含む -の最初のトークンのみをピックアップし(/
、これを他のトークンとは別に処理できるかどうかを知りたいのです。
この問題を調べるための MWE はここに提供されています:
\documentclass{article}
\usepackage[english]{babel}
\usepackage{listings}
\usepackage{xcolor}
\lstnewenvironment{lstRuby}{
\lstset{
language={},
moredelim=[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}
}
}{}
\begin{document}
\setlength{\parindent}{0pt}
\ttfamily
This is the code:
(/[a-z]+/)
This is what I want to achieve:
(\textcolor{red}{/[a-z]+/})
This is what I get using listings:
\begin{lstRuby}
(/[a-z]+/)
\end{lstRuby}
\end{document}
答え1
この回答は、質問者にとってはもはや関係ないかもしれません。しかし、この問題は本来解決すべき問題よりも解決がかなり難しく、他の人にも関係があるかもしれないので、とにかく回答を投稿します。
質問とコメントで述べたように、moredelim=**[s]
バリアントは区切りテキスト全体を 1 つのユニット/グループとして扱い、区切りグループの先頭と末尾 ( まで\aftergroup
) に任意のテキストを挿入できるようにします。その問題は、区切り文字間のテキストにも他のスタイルが適用されることにあります。一方、 はmoredelim=[s]
他のスタイルを適用せず、同じクラス (文字、その他など) の各文字チャンクに区切りグループ スタイルを適用します。これにより、区切り文字の直前と直後にのみテキストが挿入されることがなくなります。
望ましい効果を得る簡単な方法はなさそうなので、ここでは内部にフックを掛ける必要があります。 マクロ\lst@DelimOpen
と\lst@DelimClose
マクロは、リストに新しい区切り文字のペアが見つかったときのアクションを制御します。そこで、これらを再定義して、 と の 2 つのフックをインストールします\@delim@open@hook
。\@delim@close@hook
これらでは、現在どのスタイルがアクティブであるかを ( と比較することによって) 確認し、それに基づいて適切なアクションを選択できます。このアプローチでは、このような複雑な区切り文字を複数並列に使用できます。が実行される\lst@currstyle
ことに注意してください。\@delim@close@hook
前に最後の文字のチャンクが出力されるので、ここでも\aftergroup
トリックを使用して、最後のアクションを区切られたグループの最後の文字の後に移動する必要があります。
最終的な実装では、moredelim=[is][\regexstyle]{(/}{/)}
正規表現のスタイルを定義するために が使用されます。このフィールドでは、i
出力から元の区切り文字が削除されます。 は、\regexstyle
正規表現のすべての内部テキストに適用される実際のスタイルです。ここでは、明確に名前が付けられたラッパー マクロを使用するようにしてください。そうしないと、 に対するテストで\lst@currstyle
間違った結果が生じる可能性があります。\regexstyle@start
およびは、\regexstyle@end
それぞれ元の開始区切り文字と終了区切り文字の代わりにコードを挿入するマクロです。
完全な例は次のとおりです。
\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\lstnewenvironment{lstRuby}{%
\lstset{
language={},
moredelim=[is][\color{green}]{*}{*},
moredelim=[is][\regexstyle]{(/}{/)},
emphstyle=\color{blue},
emph={foo}
}%
}{}
\makeatletter
\let\orig@lst@DelimOpen=\lst@DelimOpen
\def\lst@DelimOpen#1#2#3#4#5#6\@empty{%
\orig@lst@DelimOpen{#1}{#2}{#3}{#4}{#5}{#6}\@empty
\@delim@open@hook
}
\let\orig@lst@DelimClose=\lst@DelimClose
\def\lst@DelimClose{%
\@delim@close@hook
\orig@lst@DelimClose
}
\def\@delim@open@hook{%
\def\@temp{\regexstyle}%
\ifx\lst@currstyle\@temp
\regexstyle@start
\fi
}
\def\@delim@close@hook{%
\def\@temp{\regexstyle}%
\ifx\lst@currstyle\@temp
\aftergroup\regexstyle@end
\fi
}
\def\regexstyle{\color{red}}
\def\regexstyle@start{({\regexstyle /}}
\def\regexstyle@end{{\regexstyle /})}
\makeatother
\begin{document}
\setlength{\parindent}{0pt}
\ttfamily
This is the code:
(/[a-z]+/)
This is what I want to achieve:
(\textcolor{red}{/[a-z]+/})
This is what I get using listings:
\begin{lstRuby}
text (/[a-z]+/) /[a-z]+/ *foo*
text foo (/foo|\/|foo/) *bar*
\end{lstRuby}
\end{document}