TeX와 주석을 분리하는 간단한 사전 파서?

TeX와 주석을 분리하는 간단한 사전 파서?

나는 수식과 프로그램 조각을 나란히 사용하여 수학 논문을 작성하고 싶습니다. 그러나 나는 TeX에 의해 프로그램이 표시되거나 문서화되는 것을 원하지 않으며, 원하는 경우 파일로 추출할 수만 있습니다.

내 의도는 리터럴 프로그래밍과 아무 관련이 없지만 아마도 이러한 도구 중 일부를 내 목적에 맞게 (잘못) 사용할 수 있습니까? 예를 들어 사전 파서에 대한 특수 토큰 %#을 가정하면 이러한 파일은 다음과 같습니다.

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

내 질문: TeX 문서를 준비하고 이를 다른 도구로 추가 처리하기 위해 두 개(또는 그 이상)의 다른 파일로 분할할 수 있는 도구(또는 편집기)가 있습니까? 아니면 TeX 기능을 사용하는 다른 아이디어가 있나요?

편집: jfbu의 탁월한 답변 확장: 코드 조각이 번호가 매겨진 방정식 바로 뒤에 있다고 가정하면 방정식의 번호도 코드 파일에 작성할 수 있습니까? 이는 두 출력 간의 상호 참조에 해당합니다. (이것이 가능하지 않다면 jfbu의 '정교한 답변'에 도입된 내부 스니펫 카운터를 어떻게 작성할 수 있습니까(# 또는 // ?와 같은 주석 기호가 앞에 추가됨).

답변1

외부 도구 없이 tex 내부에서 이 작업을 수행할 수 있습니다.

이 업데이트는 자동(사용자 정의 가능) 번호 매기기를 사용하여 각 코드 조각에 대해 하나의 파일을 생성합니다. 이 예에서는 4개의 코드 조각에 해당하는 filename-code-01.py, filename-code-02.py, filename-code-03.py를 생성합니다 filename-code-04.py(2개는 서문에 있음).

OP 편집에 대한 추가 업데이트: 각 출력 코드 조각의 첫 번째 줄은 이제 코드 조각 번호가 포함된 주석 줄입니다. 방정식 번호 사용에 대한 질문은 코드 조각 추출이 문서에 실제로 조판되기 전에 부분 또는 서문 코드로 수행되기 때문에 더 섬세합니다.

$ 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

내용 preparseC-code-01.py:

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

.tex소스 파일 에서 코드 조각을 식별하는 데 사용되는 줄 태그 는 입니다 %#<space><space>.

암호:

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

이것은 답변의 첫 번째 버전입니다. (쓸모없는 a를 제거하고 디버깅 라인 \makeatletter을 주석 처리했습니다 \show\LineTag.)

filename-code다음은 컴파일 시 태그가 지정된 줄 에도 추출됩니다 .

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

암호:

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

답변2

더 광범위한 도구가 있지만 fff.tex그 안에 예제를 저장하면 필요한 전부입니다 grep.sed

grep -v "^%#" fff.tex

생산하다

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

그리고

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

생산하다

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

답변3

grep또한 옵션을 사용하는 것 보다 더 읽기 쉬운 간단한 Perl 스크립트를 사용하여 수행할 수도 있습니다 sed.

#!/usr/bin/perl

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

에 저장된 문서 document.tex및 에 저장된 Perl 코드 extractComments.pl.

생산물:

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

답변4

내 생각: 코드 덩어리가 R(http://www.r-project.org/), 나는 knitr,http://yihui.name/knitr/(또는 지금은 오히려 오래된 Sweave,http://www.stat.uni-muenchen.de/~leisch/Sweave/).

그렇지 않은 경우 패키지를 사용해 보겠습니다 extract.http://ctan.org/pkg/extract, 귀하의 요구 사항에 맞는 경우.

개인적으로는 패키지로 갈 것 같아요 listings.http://mirrors.nic.cz/tex-archive/macros/latex/contrib/listings/listings.pdf, 코드는 즉시 조판될 수 있고, 필요한 경우 환경을 켜거나 끌 수 있으며(그러면 주석으로 작동함) 즉시 추출하고 기본 TeX 내부 및 외부에 코드 청크를 가질 수 있습니다. 다른 프로그램에서 동시에 컴파일할 수 있는 파일입니다.

관련 정보