Einfacher Vorparser zum Trennen von TeX und Kommentaren?

Einfacher Vorparser zum Trennen von TeX und Kommentaren?

Ich möchte eine mathematische Arbeit schreiben, die sowohl Formeln als auch Programmausschnitte enthält, und zwar nebeneinander. Allerdings möchte ich die Programme nicht von TeX anzeigen oder dokumentieren lassen, sondern sie nur bei Bedarf in eine Datei extrahieren können.

Beachten Sie, dass meine Absicht nichts mit wörtlicher Programmierung zu tun hat, aber vielleicht kann ich einige dieser Tools für meine Zwecke (missbrauchen)? Wenn wir beispielsweise ein spezielles Token %# für den Pre-Parser annehmen, könnte eine solche Datei folgendermaßen aussehen:

\documentclass[]{article}
\begin{document}
The factorial is an important function:
\begin{equation}
    n! = \prod_{k=1}^n k
\end{equation}
%#  n := 1;
%#  for k from 1 to n 
%#      n := n * k;
\end{document}

Meine Frage: Gibt es Tools (oder Editoren), die ein TeX-Dokument vorbereiten und in zwei (oder mehr) verschiedene Dateien aufteilen können, die dann von unterschiedlichen Tools weiterverarbeitet werden können? Oder gibt es andere Ideen, die TeX-Funktionen nutzen?

EDIT: In Ergänzung zu der hervorragenden Antwort von jfbu: Angenommen, der Codeausschnitt folgt unmittelbar auf eine nummerierte Gleichung, könnte die Nummer der Gleichung auch in die Codedatei geschrieben werden? Dies käme einem Querverweis zwischen den beiden Ausgaben gleich. (Wenn dies nicht möglich ist, wie kann der interne Ausschnittzähler, der in der „ausführlichen Antwort“ von jfbu eingeführt wurde, geschrieben werden (mit einem vorangestellten Kommentarzeichen wie # oder // ?).

Antwort1

Sie können dies innerhalb von Tex tun, ohne externe Tools.

Dieses Update generiert für jeden Codeausschnitt eine Datei mit automatischer (anpassbarer) Nummerierung. Dieses Beispiel erzeugt filename-code-01.py, filename-code-02.py, filename-code-03.py, filename-code-04.pyentsprechend den vier Codeausschnitten (zwei befinden sich in der Präambel).

Zusätzliches Update als Reaktion auf eine Bearbeitung des OP: Die erste Zeile jedes ausgegebenen Codeausschnitts ist jetzt eine Kommentarzeile mit der Nummer des Codeausschnitts. Die Frage nach der Verwendung der Gleichungsnummer ist heikler, da die Extraktion der Codeausschnitte als Teil des Präambelcodes erfolgt, bevor im Dokument tatsächlich etwas gesetzt wurde.

$ ls preparseC*
preparseC-code-01.py    preparseC-code-04.py    preparseC.log
preparseC-code-02.py    preparseC.aux       preparseC.tex
preparseC-code-03.py    preparseC.dvi

Die Inhalte von preparseC-code-01.py:

# Code snippet 1
n := 1;
for k from 1 to n
    n := n * k;

Der Zeilenanhang zur Identifizierung von Codeausschnitten in der .texQuelldatei lautet %#<space><space>.

Code:

\documentclass{article}

\newcounter{snippetno}

% customize \thesnippetno as desired, for example this produces
% filename-code-01.py
% filename-code-02.py
% ...
% filename-code-10.py
% etc...
% This command should be expandable
\renewcommand{\thesnippetno}
  {\jobname-code-\ifnum\value{snippetno}<10 %<- leave a space
        0\fi
   \arabic{snippetno}.py}


%%%%%%%% PREPARSING
\newread\parsein
\openin\parsein \jobname.tex

\newwrite\parseout
% this version will create one file for each code snippet
\newif\ifOutputtingLines

% adapt the following to the line tag you want to use
% the \detokenize is not needed here, but in case your tag
% uses letters, put them in it (do not use \catcode for letters
% a they may be in use in \def \endgroup etc..)
%
% THIS VERSION USES %#<space><space> AS LINE TAG
% (two spaces must be present and will be removed in the outputs)
\begingroup
%% ADDED DEFINITION OF \COMMENTTAG FOR USE IN FIRST LINE OF CODE SNIPPET FILES
\catcode`\% 12
\catcode`\# 12
\def\x{\endgroup\def\COMMENTTAG{#}\edef\LineTag{\detokenize{%#}\space\space}}
\x
%\show\LineTag % debugging

\begingroup
\edef\x{\endgroup
        \unexpanded{\def\CheckLineAux #1}\LineTag\relax \unexpanded{{#1}}
        \unexpanded{\def\CheckLine #1}\LineTag \unexpanded{#2}\relax
        \unexpanded{{\if\relax #1\relax 
                        \ifOutputtingLines\else
           \stepcounter{snippetno}%
           \immediate\openout\parseout \thesnippetno\relax
%% ------------------------ ADDED TO INSERT CODE SNIPPET NUMBER IN THE FILE
           \immediate\write\parseout 
                  {\COMMENTTAG\space Code snippet \arabic{snippetno}}%
%% ------------------------
           \OutputtingLinestrue
                        \fi
           \immediate\write\parseout {\CheckLineAux #2\relax}%
                     \else
                        \ifOutputtingLines
                          \immediate\closeout\parseout 
                          \OutputtingLinesfalse
                        \fi
                     \fi}}%
}
\x

\begingroup\endlinechar-1
\loop
  \ifeof\parsein
    % if \end{document} is not missing no need to \closeout\parseout
    % necessarily already done, and OutputtingLines toggle necessarily false
    \closein\parsein
  \else
    \readline\parsein to \tmpline
    \if\relax\tmpline\relax % found empty line
        \ifOutputtingLines\immediate\closeout\parseout
              \OutputtingLinesfalse
        \fi
    \else
        \expandafter\expandafter\expandafter \CheckLine
                \expandafter \tmpline\LineTag \relax
    \fi 
\repeat
\endgroup

%%%%%%%% END OF PREPARSING

% Some code snippets may already be put here in the preamble
% 
%#  n := 1;
%#  for k from 1 to n 
%#      n := n * k;

%#  y := 1;
%#  for k from 1 to n 
%#      y := y * (x + k -1);

% Notice that in this variant the line tag is %#<space><space>
% and is removed on output

\begin{document}
The factorial is an important function:
\[
    n! = \prod_{k=1}^n k
\]
%#  n := 1;
%#  for k from 1 to n 
%#      n := n * k;
The (so-called) Pochhammer coefficient also:
\[
    (x)_n = \prod_{k=1}^n (x+k-1)
\]
%#  y := 1;
%#  for k from 1 to n 
%#      y := y * (x + k -1);
\end{document}

Dies ist die erste Version der Antwort: (Ich habe ein \makeatletternutzloses entfernt und die \show\LineTagDebugzeile auskommentiert.)

Im Folgenden werden beim Kompilieren auch filename-codedie markierten Zeilen extrahiert.

  n := 1;
  for k from 1 to n
      n := n * k;

Code:

\documentclass{article}

%%%%%%%% PREPARSING
\newread\parsein
\openin\parsein \jobname.tex
\newwrite\parseout
\immediate\openout\parseout \jobname-code

% adapt the following to the line tag you want to use
% the \detokenize is not needed here, but in case your tag
% uses letters, put them in it (do not use \catcode for letters
% a they may be in use in \def \endgroup etc..)
\begingroup
\catcode`\% 12
\catcode`\# 12
\def\x{\endgroup\edef\LineTag{\detokenize{%#}}}
\x
%\show\LineTag % debugging
\begingroup
\edef\x{\endgroup
        \unexpanded{\def\CheckLineAux #1}\LineTag\relax \unexpanded{{#1}}
        \unexpanded{\def\CheckLine #1}\LineTag \unexpanded{#2}\relax
        \unexpanded{{\if\relax #1\relax 
                      \immediate\write\parseout {\CheckLineAux #2\relax}%
                     \fi}}%
}
\x

\begingroup\endlinechar-1
\loop
  \ifeof\parsein
    \immediate\closeout\parseout
    \closein\parsein
  \else
    \readline\parsein to \tmpline
    \if\relax\tmpline\relax\else
        \expandafter\expandafter\expandafter \CheckLine
                \expandafter \tmpline\LineTag \relax
    \fi 
\repeat
\endgroup

%%%%%%%% END OF PREPARSING

\begin{document}
The factorial is an important function:
\[
    n! = \prod_{k=1}^n k
\]
%#  n := 1;
%#  for k from 1 to n 
%#      n := n * k;
\end{document}

Antwort2

Es gibt umfangreichere Tools, aber wenn Sie Ihr Beispiel darin speichern, fff.texist grepalles sed, was Sie brauchen

grep -v "^%#" fff.tex

produziert

\documentclass[]{article}
\begin{document}
The factorial is an important function:
\[
    n! = \prod_{k=1}^n k
\]
\end{document}

Und

grep "^%#" fff.tex | sed "s/^%#//"

produziert

  n := 1;
  for k from 1 to n 
      n := n * k;

Antwort3

Dies kann auch mit einem einfachen Perl-Skript erfolgen, das für mich lesbarer ist als grepmit sedOptionen.

#!/usr/bin/perl

while(<STDIN>)
{
  if( (substr $_, 0, 2) eq "%#" )
    {
      print substr $_, 2;
    }
}

Dokument gespeichert in document.texund Perl-Code gespeichert in extractComments.pl.

Produziert:

hpek@melda:~/programming/perl$ cat document.tex |./extractComments.pl 
  n := 1;
  for k from 1 to n 
      n := n * k;
hpek@melda:~/programming/perl$ 

Antwort4

Meine Gedanken: Wenn Ihr Code-Block R ist (http://www.r-project.org/), würde ich in Betracht ziehen knitr,http://yihui.name/knitr/(oder jetzt eher der alte Sweave,http://www.stat.uni-muenchen.de/~leisch/Sweave/).

Wenn nicht, würde ich das extractPaket versuchen,http://ctan.org/pkg/extract, wenn es Ihren Anforderungen entspricht.

Persönlich würde ich wahrscheinlich das Paket wählen listings,http://mirrors.nic.cz/tex-archive/macros/latex/contrib/listings/listings.pdf, die Codes können sofort gesetzt werden, und wir können bei Bedarf seine Umgebungen ein-/ausschalten (dann würden sie sich wie Kommentare verhalten), sie im laufenden Betrieb extrahieren und wir könnten Codeblöcke innerhalb und außerhalb der Haupt-TeX-Datei haben, die gleichzeitig von anderen Programmen kompiliert werden können.

verwandte Informationen