Kann ich „moredelim“ im Paket „Listings“ verwenden, um einen regulären Ausdruck abzurufen?

Kann ich „moredelim“ im Paket „Listings“ verwenden, um einen regulären Ausdruck abzurufen?

Ich würde gerne wissen, ob es möglich ist, mit dem listingsPaket reguläre Ausdrücke hervorzuheben, damit sie wie normale Zeichenfolgenobjekte aussehen. Hinweis: Die Syntax eines regulären Ausdrucks ist nicht kontextfrei, daher kann ich keine Lösung erwarten, die 100 % der Fälle erkennt. Wie dem auch sei, ich würde beispielsweise gerne in Ruby schreiben

(/[a-z]+/)

und sagen Sie listings, dass der reguläre Ausdruck erkannt werden soll /[a-z]+/, indem die linke Klammer (als Ankerpunkt verwendet wird (um ihn von der arithmetischen Division zu unterscheiden):

\lstset{moredelim=[s][\color{red}]{(/}{/}}

Dadurch wird jedoch die linke Klammer eingefärbt – nicht nur der reguläre Ausdruck selbst. Um den Parser besser zu verstehen, habe ich die Anweisung wie folgt geändert:

 \lstset{moredelim=[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}}

Zu meiner Überraschung wird jedoch ":macro:" angewendet aufjededer Token: (/, [, a, -, z, ], und /, entdeckt vonmoredelim . Ich habe fälschlicherweise erwartet, dass ":macro:" auf dasgesamteübereinstimmender Ausdruck (/[a-z]+/. Das ist übrigens die Situation, wenn ich die Anweisung in die mit zwei Sternen versehene Version ändere:

 \lstset{moredelim=**[s][\color{red}\textcolor{black}{:macro:}]{(/}{/}}

Aber in diesem Fall wird der reguläre Ausdruck analysiert, indem listingsSchlüsselwörter im Ausdruck eingefärbt werden. Das ist nicht, was ich will. Ich will es nur als Anker verwenden, (um den regulären Ausdruck zu finden, danach will ich den Anker getrennt vom regulären Ausdruck selbst behandeln (indem ich ihm eine andere Farbe gebe).

moredelimUm genau zu sein: Ich möchte wissen, ob ich nur das erste Token in – das das – enthält – aufnehmen (/und dieses getrennt von den anderen Token behandeln kann.

Ein MWE zur Untersuchung des Problems wird hier bereitgestellt:

\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}

Antwort1

Diese Antwort ist für den Fragesteller vielleicht nicht mehr relevant. Aber da dieses Problem viel schwieriger zu lösen war, als es eigentlich hätte sein sollen, und für andere relevant sein könnte, werde ich die Antwort trotzdem posten.

Wie in der Frage und den Kommentaren erwähnt, moredelim=**[s]behandelt die Variante den gesamten abgegrenzten Text als eine Einheit/Gruppe, wodurch beliebiger Text am Anfang und auch am Ende (bis \aftergroup) der abgegrenzten Gruppe eingefügt werden kann. Das Problem dabei ist, dass auch auf den Text zwischen den Trennzeichen andere Stile angewendet werden. Andererseits moredelim=[s]wendet keine anderen Stile an, sondern wendet den Stil der Trennzeichengruppe auf jeden Block von Zeichen derselben Klasse (Buchstabe, Sonstiges usw.) an. Dadurch wird verhindert, dass Text nur direkt vor und nach den Trennzeichen eingefügt wird.

Es scheint keinen einfachen Weg zu geben, den gewünschten Effekt zu erzielen, also müssen wir uns hier in einige interne Vorgänge einklinken. Die Makros \lst@DelimOpenund \lst@DelimClosesteuern die Aktionen, wenn ein neues Trennzeichenpaar in der Auflistung gefunden wird. Also definieren wir sie neu, um zwei Hooks \@delim@open@hookund zu installieren \@delim@close@hook. In diesen können wir prüfen, welcher Stil derzeit aktiv ist (durch Vergleich mit \lst@currstyle) und basierend darauf die richtigen Aktionen auswählen. Mit diesem Ansatz können mehrere solcher ausgefallenen Trennzeichen parallel verwendet werden. Beachten Sie, dass \@delim@close@hookausgeführt wirdVorDer letzte Zeichenblock wird ausgegeben, daher müssen wir erneut den \aftergroupTrick anwenden, um die letzte Aktion nach den letzten Zeichen in der abgegrenzten Gruppe zu verschieben.

Die endgültige Implementierung verwendet, moredelim=[is][\regexstyle]{(/}{/)}um den Stil für die regulären Ausdrücke zu definieren, wobei das iFeld die ursprünglichen Trennzeichen aus der Ausgabe entfernt. \regexstyleist der tatsächliche Stil, der auf den gesamten inneren Text des regulären Ausdrucks angewendet wird. Stellen Sie sicher, dass Sie hier ein eindeutig benanntes Wrapper-Makro verwenden, da der Test andernfalls \lst@currstylezu falschen Ergebnissen führen kann. \regexstyle@startund \regexstyle@endsind die Makros, die den Code anstelle des ursprünglichen Start- bzw. Endtrennzeichens einfügen.

Hier ist das vollständige Beispiel:

\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}

Bildbeschreibung hier eingeben

verwandte Informationen