(自動)LaTeXソースファイルにコメントを付けて読みやすくします。

(自動)LaTeXソースファイルにコメントを付けて読みやすくします。

以下を行う簡単な方法を探しています。

入力する:

\begin{document}
...
\section{}
...
\subsection{}
...
\subsubsection{}
...
\section{}
...
\end{document}

出力:

\begin{document}
...
%1
\section{}
...
%1.1
\subsection{}
...
%1.1.1
\subsubsection{}
...
%2
\section{}
...
\end{document}

これの目的は、長い文書を読みやすくすることです。私はドキュメントの全体的な構成で、私がどこに適しているかを常に知りたいと思います。

答え1

何度も動作するクイックソリューションがあります。これは個人的な目的でのみ利用可能です(1)。内部編集、エラー制御などを追加することで改善できます。しかし、私もそれが役に立つと思います。アイデアは、LaTeX番号付け自体を活用することです。

したがって、まず文書にタグを追加する必要があります(とにかく良いです)。

\documentclass[12pt]{article}
\begin{document}
\section{a}
\label{sec:a}

\section{b}
\label{sec:b}

\subsection{b a}
\label{sec:ba}

\newpage

\subsection{b b}
\label{sec:bb}

\section{c}
\label{sec:c}
\end{document}

次に、Latexを以前のように実行しますwalla.tex。次に、この小さなPythonスクリプトを実行します。

#!/usr/bin/env python
#
# 
import sys
import re

labels=[]
# build a list of label
for l in open(sys.argv[1] + ".aux"):
    if l.find("newlabel{") != -1: 
        m = re.search(r'\\newlabel{(.*?)}{{(.*?)}{(.*?)}}', l)
        if m:
            labels.append("label: %s will be number: %s at page: %s" % (
                m.group(1), m.group(2), m.group(3)))
        else:
            labels.append(l)

# scan input file
for l in  open(sys.argv[1] + ".tex"):
    if l.find("\\label") != -1:
        # we have a label, try to match it
        m = re.search(r'\\label{(.*?)}', l)
        # if not m: continue ERROR not managed here
        key = m.group(1) 
        for lab in labels:
            if lab.find(key) != -1:
                # modify this to pretty print
                sys.stdout.write("%%%%%% %s\n" % lab.strip())
                break
    # output the tex file avoiding old ones
    if not l.startswith(r'%%% label'):
        sys.stdout.write(l)

を呼び出しfind_tex_labelsて実行可能にしてから実行しますfind_tex_labels walla > walla_annotated.tex(引数には拡張子がありません)。

出力にコメント付きのLaTeXファイルが表示されます。

\documentclass[12pt]{article}
\begin{document}
\section{a}
%%% label: sec:a will be number: 1 at page: 1
\label{sec:a}

\section{b}
%%% label: sec:b will be number: 2 at page: 1
\label{sec:b}

\subsection{b a}
%%% label: sec:ba will be number: 2.1 at page: 1
\label{sec:ba}

\newpage

\subsection{b b}
%%% label: sec:bb will be number: 2.2 at page: 2
\label{sec:bb}

\section{c}
%%% label: sec:c will be number: 3 at page: 2
\label{sec:c}
\end{document}

...これはすべてのタグに適用されます。 LaTeXを持たないデバイスで編集するとき、方程式などを相互参照するのに非常に便利だと思います。これで、オリジナルのwalla.texを新しいものに置き換えることができます。

同期を維持することはあなたの責任です。どこでも「%%%ラベル」コメントを使用しないでください。


脚注:

(1)私はそれを完璧にすることを何度も約束した。しかし、それを使用する唯一の人であることを考慮してエラーが表示された場合は、修正して整理する時間がありません。

答え2

比較的難しいのは、次の行が部分マーカーである場合は、更新が必要かどうかを確認するためにコメント行をバッファリングする必要があることです。そのデータが同じ行または次の行にある場合は、はるかに簡単です。

次が役に立ちます。呼び出すことpython script.py input outputも、出力を省略して標準出力に書き込むこともできます。 「python script.py xx.tex xx.tex」を実行するのではなく、一時ファイルに書き込んで元のファイルにコピーし直してください。

これにより、フォームの既存の行が更新され、変更されずに%x.y.z rest of comment残りますrest of comment。対応するコメントがまだない場合は挿入されます。セグメント化されたコマンドと同様に、特別なコメントも行の先頭から始める必要があります。

import sys

class ProcessLaTeX:
    def __init__(self, ifp, ofp):
        self.ofp = ofp
        self.prev_comment = None
        self.level = []
        for line in ifp:
            self.process(line)
        # emit last line if comment
        if self.prev_comment:
            self.ofp.write(self.prev_comment)

    def output(self, line):
        pass

    def process(self, line):
        if line[0] == '%':
            # store comment line, emitting any previously stored line
            if self.prev_comment:
                self.ofp.write(self.prev_comment)
            self.prev_comment = line
            return
        lvl = self.check_level(line)
        if lvl > -1:
            self.output_level_comment(lvl)
        if self.prev_comment:
            self.ofp.write(self.prev_comment)
            self.prev_comment = None
        self.ofp.write(line)

    def output_level_comment(self, lvl):
        if self.prev_comment: # check if we overwrite an old one
            # do not use the starting '%' and final newline
            words = self.prev_comment[1:-1].split(' ', 1)
            for c in words[0]:
                if c not in '01234567890.':
                    self.ofp.write(self.prev_comment)
                    self.prev_comment = None
                    break
        self.level.append(0) # in case this is a deeper level
        self.level[lvl] += 1
        self.level = self.level[:lvl+1] # cut of excess levels
        lvls = '%' + '.'.join([str(l) for l in self.level])
        if self.prev_comment: # overwrite the previous words[1]
            words[0] = lvls
            outs = ' '.join(words)
            if not outs[-1] == '\n':
                outs += '\n'
            self.prev_comment = None
        else:
            outs = lvls + '\n'
        self.ofp.write(outs)

    def check_level(self, line):
        if line and not line[0] == '\\':
            return -1
        cmd = line[1:].split('{', 1)[0]
        try:
            res = ['section', 'subsection', 'subsubsection',
                     'paragraph', 'subparagraph'].index(cmd)
        except ValueError:
            return -1
        return res

out = sys.stdout if len(sys.argv) < 3 else open(sys.argv[2], 'w')
pl = ProcessLaTeX(open(sys.argv[1]), out)

答え3

私の考えでは、あなたが探しているのnlセクション区切り記号オプション。からinfo nl

  • nl入力を(論理)ページに分割します。各論理ページの上部の行番号はデフォルトで 1 にリセットされます。 nlすべての入力ファイルを単一の文書として扱います。ファイル間の行番号や論理ページをリセットしません。

  • 論理ページは3つの部分で構成されています。ヘッダー歩行者。すべてのセクションは空にすることができます。それぞれは、異なるスタイルと異なるスタイルで番号付けすることができます。

  • 論理ページの各セクションの先頭は、入力ファイル内の次の区切り文字列のうちの正確に1つを含む行で表されます。

    • \:\:\:- タイトルの先頭
    • \:\: - トピックの冒頭
    • \: - フッターの始まりです。

コマンドラインで設定できるnl論理ページリミッタです。たとえば、次のようになります。-d

nl -dCC <infile

...どこCC\:文書に表示されている文字を置き換える2文字を表します。あなたの意見を考えると、これが必要だとは思わない。該当する場合は、デフォルト値を挿入していくつかの入力フィルタリングを実行します。これは、独自に再帰的にフィルタリングするように設計されたシェル関数nlと対になります。sed

sd() { n='
';     nl -bp"^\\\\$1section" -w1 -s"$n\:\:\:$n" |
       sed '/./!d;/^[0-9]/!s/^[[:blank:]]*//;/^%[0-9.]*$/h;t
            s/./%&/;x;/%/G;s//./2;/\n.*/h;s///;x;s/\n//;N
            s/\(\(.*\)\(\n\)\)\(\(.*\)\(..\)\)/\4\3\1\5/'
}

サンプルデータに似たものを入力し、出力を何度もパイプに接続しました。

sd <<\IN |sd sub | sd subsub | sd subsubsub
\begin{document}
\section{}
some ordinary lines
\subsection{}
whatever
\subsubsection{}
\subsection{}
\subsubsection{}
\subsubsubsection{}
\section{}
\subsection{}
\end{document}
IN

上記のように実行します。

\begin{document}
%1
\section{}
some ordinary lines
%1.1
\subsection{}
whatever
%1.1.1
\subsubsection{}
%1.2
\subsection{}
%1.2.1
\subsubsection{}

\:\:\:
%1.2.1.1
\:\:
\subsubsubsection{}
%2
\section{}
%2.1
\subsection{}
\end{document}

ご覧のとおり、フィルタ操作は完全完了しましたが、操作は完了したようです。入力本文は入力内容に応じて番号が付けられ、nl各論理ページの数が数え始めます。-b-bp'attern'ただ論理ページヘッダー区切り記号\:\:\:

したがって...出力をフィルタリングします。すでにsed区切り文字 arg には区切り文字セットが含まれており、デフォルトでは次のステップで部分区切り文字を見つけるために少し並べ替えます。ただし、前のスペースに最後の行のコピーも保持します。数字で始まる行に出会ったときに予約されたスペースが空でない場合は、その行を予約されたスペースの内容に追加し、その後に 。そしてジャガイモも。nl-ssednlsed^%[0-9.]*$h.

それでも - 私が言ったように、まだ終わっていません。最後に、出力にセクション区切り文字と空白行が残りました。したがって、クリーニングするには、次の手順を実行します。

sd <<\IN |sd sub | sd subsub | sd subsubsub | grep -v '^\\:\|^$'
\begin{document}
\section{}
some ordinary lines
\subsection{}
whatever
\subsubsection{}
\subsection{}
\subsubsection{}
\subsubsubsection{}
\subsubsection{}
\subsubsubsection{}
\section{}
\subsection{}
\end{document}
IN

出力:

\begin{document}
%1
\section{}
some ordinary lines
%1.1
\subsection{}
whatever
%1.1.1
\subsubsection{}
%1.2
\subsection{}
%1.2.1
\subsubsection{}
%1.2.1.1
\subsubsubsection{}
%1.2.2
\subsubsection{}
%1.2.2.1
\subsubsubsection{}
%2
\section{}
%2.1
\subsection{}
\end{document}

関連情報