You can do this from inside tex, without external tools.
This update generates one file for each code snippet with automatic (customizable) numbering. This example produces filename-code-01.py
, filename-code-02.py
, filename-code-03.py
, filename-code-04.py
corresponding to the four code snippets (two are in the preamble).
Additional update in response to an edit to the OP: the first line of each output code snippet is now a comment line with the number of the code snippet. The question about using the equation number is more delicate, as the extraction of the code snippets is done as part or the preamble code, before anything has been actually typeset in the document.
$ 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
The contents of preparseC-code-01.py
:
# Code snippet 1
n := 1;
for k from 1 to n
n := n * k;
The line tag used to identify code snippets in the .tex
source file is %#<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}
This is the first version of the answer: (I have removed a \makeatletter
which was useless, and commented out the \show\LineTag
debugging line)
The following will on compilation also extract to filename-code
the tagged lines.
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}
\documentclass{ltxdoc}