基本的に、sed
この仕事には間違ったツールです。sed
ファイルを前処理し、ファイルを処理する新しいスクリプトを生成するスクリプトを作成できるかもしれませんがsed
、タスク用のはるかに優れたツールがたくさんある場合、あなたは藁をもつかむことになります。私は Perl にたどり着きます (しかし、Perl は 20 年以上前に学び、Python はほんの数年前に学びました)、Python でもそれを扱うことができますawk
。問題の一部は、段落 2 の開始に到達するまで、段落 1 のすべてのテキストを保存しなければならないことです。そうして初めて、段落 1 の実際のテキストの生成を開始できます。
スクリプトが段落の内容をホールド スペースにキャプチャしてsed
も、「間違ったツールです」というコメントは有効なままだと思います。sed
これらは、角括弧で始まらない行になります。問題は、角かっこのある行に到達したときに、角かっこの内容の代わりにホールド スペースに行の末尾を代入する正規表現を記述する必要があることです。それには一種の「動的正規表現」が必要です。たとえば、1 つの段落に 9 つ以上の脚注が存在しないことを知っていたとしても、コードを 9 回書き出す何らかのハックを考えることができたとしても、置換文字列を適切な場所に書き出すにはまだ問題があります。
これは、Perl で作成された単純なスクリプト (Perl で作成された非常に複雑なスクリプトではありません) です。「ぐるぐる回るループ」(3 つのネストされたループ) は、理解するのが少し難しいです。
#!/usr/bin/env perl
use strict;
use warnings;
my $para = "";
TEXT:
while (<>)
{
NOTES:
while (m/^\s*\[(\d+)]\s+(.*)/)
{
my $tag = $1;
my $note = $2;
$para =~ s/\[$tag]/\\footnote{$note}/m;
while (<>)
{
last if $_ =~ m/^\s*\[/;
if ($_ !~ m/^\s*$/)
{
print $para;
$para = "";
last NOTES;
}
}
last TEXT if eof;
}
$para .= $_;
}
print "$para";
入力ファイルが与えられた場合:
Paragraph one. This is the first place [1] of paragraph one. This is the second place [2] of paragraph one.
[1] annotation one of paragraph one
[2] annotation two of paragraph one
Paragraph two. This is the first place [1] of paragraph two. This is the second place [2] of paragraph two.
[1] annotation one of paragraph two
[2] annotation two of paragraph two
そのファイルからのこのスクリプトの出力は次のとおりです。
Paragraph one. This is the first place \footnote{annotation one of paragraph one} of paragraph one. This is the second place \footnote{annotation two of paragraph one} of paragraph one.
Paragraph two. This is the first place \footnote{annotation one of paragraph two} of paragraph two. This is the second place \footnote{annotation two of paragraph two} of paragraph two.
スクリプトは何をしますか?
外側のループ (ラベル)は、EOF までTEXT
行を読み込みます。$_
というラベルの付いたループはNOTES
、段落の後の素材を次の段落の開始まで処理します。角括弧内の数字で始まるため、それが脚注行であることを認識します (スペースでインデントされている可能性があり、右角括弧の後にスペースがあることは間違いありません)。そのような行が見つかると、番号が に保存され$tag
、置換テキスト (単一行である必要があります。ここでは複数行の脚注はありません) が保存され$note
ます。次に、保存された段落の角括弧内のタグの最初の出現が、脚注表記と注記のテキストに置き換えられます (これは、 の 1 回の実行ではほぼ不可能な部分でありsed
、脚注番号が繰り返されることを考えると段落をまたいで、sed
問題あり)。その置換を行うと (置換する一致がないかどうかは気にしません)、次の行を読み取ります。ここからループ (およびヘッド) が動き始めます。新しく読み取られた行がメモ行である場合、最初の行はlast
最も内側から出て、ループwhile
の次の繰り返しに戻ります。NOTES
行が空白行と一致しない場合、次の段落の最初の行を読み取ったに違いないため、前の段落を印刷し (これには、行うべき置換と同じ数の置換が行われます)、保存された段落を空にします。NOTES
ループを終了します。それ以外の場合は、メモの途中にある空白行を無視してください。
ループの後、EOF を取得したかどうかを確認し、取得した場合はメイン ループを終了します。それ以外の場合は、読み取ったばかりの段落行を保存した段落に追加します。
最後に、最後に保存した段落を印刷します。
これは徹底的にテストされていません。欠落したメモへの参照を含む段落、参照のないメモ、またはメモの順序が正しくない段落を生成していません。問題を無視することで、それらを「処理」すると思います。見つからないメモへの参照がまだあり、参照されていないメモは単に出力に表示されません。段落内に同じノート ナンバーの参照が 2 回表示され、段落の後にノート ナンバーが 1 つしかない場合、2 番目以降のノート ナンバーは無視されます。同じ音符番号が 2 回表示され ('text[1] more[1]')、段落の後の音符がその番号を繰り返す場合 ('[1] note 1A'、'[1] note 1B')、最初の音符は'note 1A' に置き換え、2 番目を 'note 1B' に置き換えます。複数行の段落はテストしていません (ただし、問題はないと思います)。
複数行の脚注の処理は、読者の課題です (完全に簡単というわけではありません)。それ以外の場合は、空白行、別の脚注行、または次の段落の開始が見つかるまで、複数行の脚注を置き換えることはできません。