한 쌍의 교정기를 필터링하는 방법

한 쌍의 교정기를 필터링하는 방법

내 문서에 .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.빈 쌍이 있을 수도 {}있고 다른 쌍이 포함될 수도 있습니다 {}. 예를 들어 다음과 같습니다.

\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를 사용하고 있는데 awk, awkPOSIX를 사용하기가 번거롭습니다(누락되어 gensub두 번 이상 사용했습니다).

#!/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

Perl Text::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).

관련 정보