Parsen bei \newcommand unterdrücken?

Antwort erstellen


Diese Frage dient dazu, das automatisierte Versenden von Formularen durch Spam-Bots zu verhindern.
Smilies
:D :) :( :o :shock: :? 8) :lol: :-x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen:

BBCode ist eingeschaltet
[img] ist eingeschaltet
[flash] ist ausgeschaltet
[url] ist eingeschaltet
Smilies sind eingeschaltet

Die letzten Beiträge des Themas

Ich habe die Datenschutzerklärung gelesen und bin damit einverstanden.

   

Wenn du eine Datei oder mehrere Dateien anhängen möchtest, gib die Details unten ein.

Ansicht erweitern Die letzten Beiträge des Themas: Parsen bei \newcommand unterdrücken?

Konkrete Anwendung

von Rolli » Fr 8. Feb 2019, 14:30

Ohje, was habe ich da wieder angerichtet! Ich dachte, es sei ganz einfach ...
Zunächst Euch vielen Dank für die Informationen - wieder was gelernt.
So richtig weiter komme ich damit aber nicht. Ich möchte Folgendes tun:
Im Dateisystem habe ich hierarchisch verschiedene Dokumente, und ich möchte eine Übersicht erstellen, welche Unterverzeichnisse und Dokumente vorhanden sind. Das Ganze soll anklickbar sein - so dass sich - je nach Eintragtyp - automatisch ein Explorerfenster (bei Verzeichnissen), oder ein PDF-Betrachter usw. öffnet.
Das funktioniert auch alles ganz gut - bis auf den Umstand, dass es leider Dateienamen gibt, in denen ein Underscore _ ist; möglicherweise auch ein Prozent %. Unten ein konkretes Beispiel.

Mit alltt geht das leider nicht, da ich in meinem \aEntry das \item drin habe.
Ich fürchte, da muss ich mich mit \catcode auseinandersetzen - oder hat jemand eine einfachere Idee?

Gruß vom Rolli
\documentclass{scrartcl}
\usepackage{xcolor}
\usepackage{csquotes}
\usepackage{hyperref}

\begin{document}

\newcommand\aEntry[4]{% #1 FILE oder DIR    #2 Farbe    #3 Link    #4 Beschreibungstext
   \item [\color{#2}#1] \href[pdfnewwindow]{run:#3}{\color{#2}\textquote{#3}}{\color{#2}: #4}
}

\begin{description}
   \aEntry{FILE}{black}{Uebersicht.pdf}{Diese Datei}
   \aEntry{DIR~}{black}{Beispiele}{In diesem Unterverzeichnis sind die Beispiele}
   \begin{description}
      \aEntry{FILE}{red}{Beispiele/Beispiel1.tex}{Hier ist das erste Beispiel}
      \aEntry{FILE}{black}{Beispiele/Beispiel2.tex}{Hier ist das zweite Beispiel}
      \aEntry{DIR~}{black}{Beispiele/Fortgeschritten}{In diesem Unterverzeichnis sind kompliziertere Beispiele}
      \begin{description}
         \aEntry{FILE}{red}{Beispiele/Fortgeschritten/Beispielx.tex}{Hier ist ein kompliziertes Beispiel}
      \end{description}
   \end{description}
\end{description}

\end{document}

von Gast » Fr 8. Feb 2019, 10:23

Anonymous hat geschrieben:Ob das eine Rolle spielt, hängt vom tatsächlichen Einsatzzweck ab.
Verwendet man beispielsweise Umlaute mit pdflatex, so spielt das recht schnell eine Rolle:
\documentclass{scrartcl}
\usepackage[T1]{fontenc} %wichtig für korrekte Ausgabe
\begin{document}
\newcommand{\myCommand}[1]{\detokenize{#1}}

\verb+Märchen+ vs. \myCommand{Märchen}
\end{document}
Mit lualatex ist zumindest das hingegen kein Problem.
\documentclass{scrartcl}
\usepackage{fontenc}
\begin{document}
\newcommand{\myCommand}[1]{\detokenize{#1}}

\verb+Märchen+ vs. \myCommand{Märchen}
\end{document}
Die Ausgabe von \detokenize ist also nicht nur vom Font-Encoding, sondern auch von der Eingabecodierung abhängig und so indirekt auch von der Engine.

von Gast » Fr 8. Feb 2019, 10:18

u_fischer hat geschrieben:Nun, die einfache Variante wäre \detokenize.
Wobei \detokenize Leerzeichen nach vermeintlichen Befehlen einfügt:
\documentclass{scrartcl}
\usepackage[T1]{fontenc} %wichtig für korrekte Ausgabe
\begin{document}
\newcommand{\myCommand}[1]{\detokenize{#1}}

\verb+Hello_world!\par\par+

\myCommand{Hello, world!\par\par} % funktioniert natürlich
\myCommand{Hello_world!\par\par}  %
\end{document}
und die Ausgabe eben wieder vom Font-Encoding abhängt. Ob das eine Rolle spielt, hängt vom tatsächlichen Einsatzzweck ab.

von u_fischer » Fr 8. Feb 2019, 09:27

Nun, die einfache Variante wäre \detokenize. Aber ich habe den Verdacht, dass du nicht wirklich willst, dass dein Befehl sich verbatim verhält, sondern dass du nur bestimmte Eingaben (wie _) anders behandeln willst.

\documentclass{scrartcl}
\usepackage[T1]{fontenc} %wichtig für korrekte Ausgabe
\begin{document}
\newcommand{\myCommand}[1]{\detokenize{#1}}

\verb+Hello_world!\par+

\myCommand{Hello, world!\par} % funktioniert natürlich
\myCommand{Hello_world!\par}  % 
\end{document} 

von Gast » Fr 8. Feb 2019, 08:10

Das Zauberwort heißt \catcode. Der Category-Code eines Zeichens bestimmt, was für ein Token beim Einlesen des Quellcodes gebildet wird. Das bedeutet, sobald ein Zeichen gelesen ist, ist es zu spät dafür.

Genau damit arbeitet \verb. Deshalb ist \verb auch nicht so definiert, dass es selbst ein Argument einliest. Im LaTeX-Kern wirst Du also weder etwas wie \newcommand*{\verb}[1] noch etwas wie \def\verb#1 finden. Stattdessen beginnt es mit \def\verb{. Dann wird als zentrales Element eine Gruppe geöffnet, Category-Codes geändert (u. a. über \dospecials) und weitere Umdefinierungen vorgenommen und erst dann wird das Argument gelesen, wobei das im Fall on \verb auch noch ziemlich ungewöhnlich erfolgt, weil \verb eine sehr spezielle Form eines Argument verarbeitet. Am Ende muss natürlich auch noch die Gruppe wieder geschlossen und damit die Änderungen rückgängig gemacht werden.

Es wird also nicht etwa das Parsen unterdrückt, sondern der Parser umprogrammiert, bevor das Argument gelesen wird.

Es ist zu beachten, dass einige Zeichen im normalen Encoding von Fonts gar nicht in der gewünschten Form enthalten sind. Beispielsweise würde ein \ im normalen Textfont nicht funktionieren, weil auf der entsprechenden Code-Position ein anderes Zeichen liegt. Deshalb ergeben beispielsweise \string\test und \texttt{\string\test} unterschiedliche Ergebnisse.

In deinem Fall kommt erschwerend hinzu, dass Du offenbar gar nicht das Verhalten von \verb willst. Das würde nämlich \par als Text ausgeben und keinen Absatz erzeugen. Damit käme eher die Verwendung der alltt-Umgebung des Pakets alltt in Frage, beispielsweise in der Form:
\documentclass{scrartcl}
\usepackage{alltt}

\makeatletter
\newcommand{\myCommand}{%
  \begin{alltt}\@myCommand
}
\newcommand{\@myCommand}[1]{#1\end{alltt}}
\makeatother

\begin{document}
\myCommand{Hello, world!\par} % funktioniert natürlich
\myCommand{Hello_world!\par}  % funktioniert natürlich auch
\end{document}
Die Gruppe (in Form der Umgebung alltt wird hier also geöffnet und damit Category-Codes geändert, bevor \@myCommand das Argument liest.

An dem Beispiel kann man auch zeigen, dass das ganze von \ttfamily abhängt:
\documentclass{scrartcl}
\usepackage{alltt}

\makeatletter
\newcommand{\myCommand}{%
  \begin{alltt}\normalfont\@myCommand
}
\newcommand{\@myCommand}[1]{#1\end{alltt}}
\makeatother

\begin{document}
\myCommand{Hello, world!\par} % funktioniert natürlich
\myCommand{Hello_world!\par}  % funktioniert natürlich auch
\end{document}
bringt nicht das gewünschte Ergebnis, weil normalerweise an der Code-Position von _ ein anderes Zeichen liegt. Man müsste also diverse Zeichen noch explizit umdefinieren, beispielsweise:
\documentclass{scrartcl}
\usepackage{alltt}

\makeatletter
\newcommand{\myCommand}{%
  \begin{alltt}\normalfont\myCommand@extraspecials\@myCommand
}
\newcommand{\@myCommand}[1]{#1\end{alltt}}
\begingroup
\catcode`\_=\active
\gdef\myCommand@extraspecials{%
  \catcode`\_=\active
  \let_=\_
}
\makeatother

\begin{document}
\myCommand{Hello, world!\par} % funktioniert natürlich
\myCommand{Hello_world!\par}  % funktioniert natürlich auch
\end{document}
Du siehst, das ganze kann je nachdem, was man braucht und will, recht aufwändig werden. Dagegen ist es recht einfach, ein zweites \verb zu definieren, also eine Anweisung, die sich tatsächlich wie \verb verhällt:
\documentclass{scrartcl}
\newcommand*{\myCommand}{}
\let\myCommand\verb

\begin{document}
\myCommand*+Hello, world!\par+ % funktioniert natürlich
\myCommand+Hello_world!\par+  % funktioniert natürlich auch
\end{document}
Wenn Du Dich tiefer mit Category-Codes und der Funktion des Scanners und des Parsers von TeX beschäftigen willst, sei auf TeX by Topic verwiesen (ist seit einigen Jahren frei erhältlich und zumindest bei TeX Live sogar dabei). Daneben natürlich auf das Standardwerk zu TeX: The TeXbook. Letzteres ist wirklich schwere Kost. Wer das verstanden hat, hat dann aber auch verstanden, wie TeX funktioniert und warum einige scheinbar einfache Dinge nicht ganz einfach zu lösen sind.

Parsen bei \newcommand unterdrücken?

von Rolli » Do 7. Feb 2019, 23:33

Hallo allerseits,

ich habe mal wieder ein (vermutlich recht kleines) Problem, das ich aber nicht alleine hin bekomme - mein altes Thema: Ich suche schon seit längerer Zeit, aber vermutlich mit dem falschen Suchbegriff (schäm).

Die Frage ist eigentlich recht simpel: Was muss ich \newcommand mitgeben bzw. ändern, damit der LaTeX-Compiler die übergebenen Argumente nicht parst, sondern 1:1 weiter gibt? Und dass mein selbst definiertes Makro das ebenfalls fehlerfrei verarbeiten kann? Sozusagen etwas in der Art, wie es verbatim macht.

Im Minimalbeispiel möchte ich, dass der zweite \myCommand-Aufruf einfach Hello_world! setzt, ohne das Gemeckere, dass eine Mathematik-Umgebung fehle.
\documentclass{scrartcl}

\begin{document}
\newcommand{\myCommand}[1]{#1}

\myCommand{Hello, world!\par} % funktioniert natürlich
\myCommand{Hello_world!\par}  % bringt Fehler
\end{document}
Danke für Eure Gedankenanstöße!

Gruß vom Rolli[/m]

Nach oben