
我想知道是否可以使用該listings
套件來突出顯示正規表示式,以使它們看起來像普通的字串物件。注意:正規表示式的語法不是上下文無關的,因此我不能指望有一個可以識別 100% 情況的解決方案。無論如何,在例如 Ruby 中我想寫
(/[a-z]+/)
並告訴透過使用左括號作為錨點來listings
識別正規表示式(以使其與算術除法分開):/[a-z]+/
(
\lstset{moredelim=[s][\color{red}]{(/}{/}}
但是,這使得左括號著色 - 不僅僅是正規表示式本身。為了更好地理解解析器,我將語句修改為:
\lstset{moredelim=[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}}
然而,令我驚訝的是,「:macro:」適用於每個標記的數量:(/
、[
、a
、-
、z
、]
和/
,由 發現moredelim
。我錯誤地期望「:macro:」會被應用到全部的匹配的表達(/[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]
變體將整個分隔文字視為一個單元/群組,這允許在分隔組的開頭和末尾插入任意文字(通過\aftergroup
)。問題是,其他樣式也套用於分隔符號之間的文字。另一方面,moredelim=[s]
不套用其他樣式,而是將分隔符組樣式套用到同一類別的每個字元區塊(字母、其他等)。這可以防止僅在分隔符號之前和之後插入文字。
似乎沒有一種簡單的方法可以達到預期的效果,因此我們必須在這裡掛鉤一些內部結構。\lst@DelimOpen
和巨集\lst@DelimClose
控制在清單中找到新分隔符號對時的操作。所以我們重新定義它們來安裝兩個鉤子\@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}