一対の校正器をフィルタリングする方法

一対の校正器をフィルタリングする方法

マイドキュメントに.toc(カタログファイル)があります.tex

これには多くの行が含まれており、その一部は次の形式です。

\contentsline {part}{Some title here\hfil }{5}
\contentsline {chapter}{\numberline {}Person name here}{5}

私はgrep存在する方法partと存在する方法を知っていますchapter。しかし、この行をフィルタリングして、次csvのファイルに出力を保存したいと思います。

{Some title here},{Person name here},{5}

それとも校正器がないか

Some title here,Person name here,5

1.もちろん、最後のペアの数字(ページ番号)は両方の行と{}同じであるため、2行目だけをフィルタリングできます。

2.空のペアがあって{}も、他のペアも含まれている場合があります{}。たとえば、次のようになります。

\contentsline {part}{Title with math $\frac{a}{b}$\hfil }{15}

フィルタリングする必要があります

Title with math $\frac{a}{b}$

編集1:以下を使用して、行の末尾に中括弧なしで数字を取得できます。

grep '{part}' file.toc | awk -F '[{}]' '{print $(NF-1)}'

編集2:chapterラインをフィルタリングしてジャンクを削除できます。

grep '{chapter}' file.toc | sed 's/\\numberline//' | sed 's/\\contentsline//' | sed 's/{chapter}//' | sed 's/{}//' | sed 's/^ {/{/'

空白のない出力は次のとおりです。

    {Person name here}{5}

編集3:part出力をフィルタリングして整理できました

    \contentsline {chapter}{\numberline {}Person name here}{5}

返品

{Title with math $\frac{a}{b}$}{15}

答え1

これはGNUを使用していますがawkawkPOSIXを使用するのが面倒です(欠けていてgensub2回以上使用しました)。

#!/usr/bin/env gawk

function join(array, result, i)
{
    result = array[0];
    end = length(array) - 1;
    for (i = 1; i <= end; i++)
        result = result "," array[i];
    return result;
}
function push(arr, elem)
{
    arr[length(arr)] = elem;
}

# split("", arr) is a horribly unreadable way to clear an array
BEGIN { split("", arr); }

/{part}|{chapter}/ {
    l = gensub(".*{(.+)}{(.+)}{([0-9]+)}$", "\\1,\\3,\\2", "g");
    if ("part" == substr(l, 0, 4)) {
        if (length(arr) > 0) { print join(arr); }
        split("", arr);
        push(arr, gensub("^(.*),(.*),(.*)$", "\\2,\\3","g", l));
    } else {
        push(arr, gensub("^(.*),(.*),(.*)$", "\\3","g", l));
    }
}

END { print join(arr); }

これは正規表現が貪欲であることを利用するので、一致は毎回行全体を取得します。最初に考えたよりもはるかに多くの努力が必要でした。

次のように入力します。

\contentsline {part}{Some title here\hfil }{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {part}{Some title here\hfil }{7}
\contentsline {chapter}{\numberline {}Person name here}{7}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{7}
blah blah
\contentsline {part}{Some title here\hfil }{9}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{9}

私達は次を作り出しますcat input | awk -f the_above_script.awk

5,Some title here\hfil ,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here
7,Some title here\hfil ,\numberline {}Person name here,\numberline {}Person name here
9,Some title here\hfil ,\numberline {}Person name here

ページ番号は、埋め込み後に発生する{part}すべての情報から取得されます。これにより、本の一部に複数の章を含めることができます。{chapter}{part}

答え2

PerlText::Balancedモジュールを使用すると、次のようにトップレベルの{}コンテンツを抽出できます。

#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw(extract_bracketed);

# this will of course fail if the input is one multiple lines, as this
# is only a line-by-line parser of standard input or the filenames
# passed to this script
while ( my $line = readline ) {
    if ( $line =~ m/\\contentsline / ) {
        my @parts = extract_contents($line);
        # emit as CSV (though ideally instead use Text::CSV module)
        print join( ",", @parts ), "\n";
    } else {
        #print "NO MATCH ON $line";
    }
}

sub extract_contents {
    my $line = shift;
    my @parts;
    # while we can get a {} bit out of the input line, anywhere in the
    # input line
    while ( my $part = extract_bracketed( $line, '{}', qr/[^{]*/ ) ) {
        # trim off the delimiters
        $part = substr $part, 1, length($part) - 2;
        push @parts, $part;
    }
    return @parts;
}

いくつかの入力を使用すると、次のようになります。

% < input 
not content line
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {part}{Title with math $\frac{a}{b}$\hfil }{15}
also not content line
% perl parser input
chapter,\numberline {}Person name here,5
part,Title with math $\frac{a}{b}$\hfil ,15
% 

答え3

存在するTxR

@(repeat)
\contentsline {part}{@title\hfil }{@page}
@  (trailer)
@  (skip)
\contentsline {chapter}{\numberline {}@author}{@page}
@  (do (put-line `@title,@author,@page`))
@(end)

サンプル:

\lorem{ipsum}
\contentsline {part}{The Art of The Meringue\hfil }{5}
a
b
c
j
\contentsline {chapter}{\numberline {}Doug LeMonjello}{5}


\contentsline {part}{Parachuting Primer\hfil }{16}

\contentsline {chapter}{\numberline {}Hugo Phirst}{16}

\contentsline {part}{Making Sense of $\frac{a}{b}$\hfil }{19}

\contentsline {part}{War and Peace\hfil }{27}

\contentsline {chapter}{\numberline {}D. Vide}{19}

\contentsline {part}{War and Peace\hfil }{19}

ランニング:

$ txr title-auth.txr data
The Art of The Meringue,Doug LeMonjello,5
Parachuting Primer,Hugo Phirst,16
Making Sense of $\frac{a}{b}$,D. Vide,19

メモ:

  • なぜなら@(trailer)使用時に作成者が提供した行がその部分に厳密に従う必要はありません。データは、複数の\contentsline {part}要素とともに、chapterページ番号に一致する行で始まることができます。
  • @(skip)残りの完全なデータを取得することを意味します。数値パラメータを追加して範囲を制限すると、パフォーマンスが向上する可能性があります。{chapter}一致が常に次の50行以内に見つかったと仮定できる場合は、{part}使用できます@(skip 50)

関連情報