1

テキストの注釈を脚注の形に変換したい。テキストの最小限の例を次に示します。

パラグラフ1。これは段落 1 の最初の場所 [1] です。これは段落 1 の 2 番目の場所 [2] です。

[1] 段落 1 の注釈 1

[2] 段落 1 の注釈 2

段落 2。これは段落 2 の最初の場所 [1] です。これは段落 2 の 2 番目の場所 [2] です。

[1] 段落 2 の注釈 1

[2] 段落 2 の注釈 2

各段落の終わりには、ラベル [1] で始まるいくつかの注釈があります。各注釈は 1 つの段落を形成します。

私がやりたいことは、これらの注釈をラテックス構文でテキストに挿入することです。サンプルテキストの望ましい出力は、

パラグラフ1。これは、段落 1 の最初の場所\footnote{段落 1 の注釈 1}です。これは、段落 1 の 2 番目の\footnote{段落 1 の注釈 2}です。

段落 2。これは、段落 2 の最初の場所\footnote{段落 2 の注釈 1}です。これは、段落 2 の 2 番目の\footnote{段落 2 の注釈 1}です。

これは、パターンを一致させることによる単なる置き換えではありません。段落ごとに実行する必要がある場合があります。最も簡単な方法は何だと思いますか。

編集:sedを使用するために可能な解決策を思いつきました。

注釈の前にある改行を削除し、

パラグラフ1。これは段落 1 の最初の場所 [1] です。これは段落 1 の 2 番目の場所 [2] です。[1] 段落 1 の注釈 1 [2] 段落 1 の注釈 2

段落 2。これは段落 2 の最初の場所 [1] です。これは段落 2 の 2 番目の場所 [2] です。[1] 段落 2 の注釈 1 [2] 段落 2 の注釈 2

パターンに合わせる

[1] テキスト1 [1] テキスト2 [2]

そしてそれを

テキスト2 テキスト1 [2]

基本的に最初の [1] は、注釈を挿入する場所です。[1] と [2] の間にあるものは、再配置される注釈です。

これらの質問は関連しています:特定の行の改行/改行文字 を削除する sed を使用してパターンの前に改行/改行を削除するにはどうすればよいですか?しかし、正規表現の知識が不足しているため、これらのコードを機能させることはできません.

4

2 に答える 2

1

基本的に、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' に置き換えます。複数行の段落はテストしていません (ただし、問題はないと思います)。

複数行の脚注の処理は、読者の課題です (完全に簡単というわけではありません)。それ以外の場合は、空白行、別の脚注行、または次の段落の開始が見つかるまで、複数行の脚注を置き換えることはできません。

于 2014-09-06T19:22:24.140 に答える
0

あまり冗長でない (そしてあまり文書化されていない) perl バージョン

perl -00 -pe '
    @markers = m{(\[\d+\])}g;
    for $i (0..$#markers) {
        $footnote = <>;
        ($marker, $text) = $footnote =~ m{(\[\d+\])\s+(.*)};
        s{\Q$marker\E}{\\footnote{$text}};
    }
' file

これは、段落に 5 つの脚注マーカーがある場合、その段落に 5 つの脚注が続くことを前提としています。

于 2014-09-06T20:44:42.087 に答える