Подтвердить что ты не робот

Как снять верхние и нижние колонтитулы с текстов проекта Gutenberg?

Я пробовал различные методы, чтобы лишить лицензию из текстов Project Gutenberg, для использования в качестве корпуса для проекта изучения языка, но я не могу придумать неконтролируемый, надежный подход. Лучшая эвристика, которую я придумал до сих пор, снимает первые двадцать восемь строк и последние 398, которые работали для большого количества текстов. Любые предложения относительно способов автоматического разбиения текста (что очень похоже на множество текстов, но с небольшими различиями в каждом случае и нескольких разных шаблонов) текст был лишен точно, было бы очень полезно.

4b9b3361

Ответ 1

Ты не шутишь. Это почти так, как если бы они пытались сделать работу AI-полной. Я могу думать только о двух подходах, ни один из них не идеален.

1) Настройте script в, скажем, Perl, для решения наиболее распространенных шаблонов (например, посмотрите на фразу "созданный", продолжайте идти к следующей пустой строке и разрежьте ее), но введите множество утверждений о том, что ожидается (например, следующий текст должен быть заголовком или автором). Таким образом, когда шаблон не удастся, вы это узнаете. В первый раз, когда шаблон терпит неудачу, сделайте это вручную. Во второй раз измените script.

2) Попробуйте Amazon Mechanical Turk.

Ответ 2

Я также хотел, чтобы инструменты, чтобы заголовки и нижние колонтитулы Project Gutenberg годами играли с обработкой на естественном языке, не загрязняя анализ шаблоном, смешанным с etxt. Прочитав этот вопрос, я, наконец, вытащил палец и написал фильтр Perl, который вы можете пропустить в любой другой инструмент.

Он используется как конечный автомат с использованием регулярных выражений. Это написано легко понять, поскольку скорость не является проблемой с типичным размером etexts. Пока это работает на пару десятков etexts, которые у меня есть здесь, но в дикой природе наверняка будет много вариантов, которые нужно добавить. Надеюсь, код достаточно ясен, чтобы кто-то мог добавить к нему:


#!/usr/bin/perl

# stripgutenberg.pl < in.txt > out.txt
#
# designed for piping
# Written by Andrew Dunbar (hippietrail), released into the public domain, Dec 2010

use strict;

my $debug = 0;

my $state = 'beginning';
my $print = 0;
my $printed = 0;

while (1) {
    $_ = <>;

    last unless $_;

    # strip UTF-8 BOM
    if ($. == 1 && index($_, "\xef\xbb\xbf") == 0) {
        $_ = substr($_, 3);
    }

    if ($state eq 'beginning') {
        if (/^(The Project Gutenberg [Ee]Book( of|,)|Project Gutenberg )/) {
            $state = 'normal pg header';
            $debug && print "state: beginning -> normal pg header\n";
            $print = 0;
        } elsif (/^$/) {
            $state = 'beginning blanks';
            $debug && print "state: beginning -> beginning blanks\n";
        } else {
            die "unrecognized beginning: $_";
        }
    } elsif ($state eq 'normal pg header') {
        if (/^\*\*\*\ ?START OF TH(IS|E) PROJECT GUTENBERG EBOOK,? /) {
            $state = 'end of normal header';
            $debug && print "state: normal pg header -> end of normal pg header\n";
        } else {
            # body of normal pg header
        }
    } elsif ($state eq 'end of normal header') {
        if (/^(Produced by|Transcribed from)/) {
            $state = 'post header';
            $debug && print "state: end of normal pg header -> post header\n";
        } elsif (/^$/) {
            # blank lines
        } else {
            $state = 'etext body';
            $debug && print "state: end of normal header -> etext body\n";
            $print = 1;
        }
    } elsif ($state eq 'post header') {
        if (/^$/) {
            $state = 'blanks after post header';
            $debug && print "state: post header -> blanks after post header\n";
        } else {
            # multiline Produced / Transcribed
        }
    } elsif ($state eq 'blanks after post header') {
        if (/^$/) {
            # more blank lines
        } else {
            $state = 'etext body';
            $debug && print "state: blanks after post header -> etext body\n";
            $print = 1;
        }
    } elsif ($state eq 'beginning blanks') {
        if (/<!-- #INCLUDE virtual=\"\/include\/ga-books-texth\.html\" -->/) {
            $state = 'header include';
            $debug && print "state: beginning blanks -> header include\n";
        } elsif (/^Title: /) {
            $state = 'aus header';
            $debug && print "state: beginning blanks -> aus header\n";
        } elsif (/^$/) {
            # more blanks
        } else {
            die "unexpected stuff after beginning blanks: $_";
        }
    } elsif ($state eq 'header include') {
        if (/^$/) {
            # blanks after header include
        } else {
            $state = 'aus header';
            $debug && print "state: header include -> aus header\n";
        }
    } elsif ($state eq 'aus header') {
        if (/^To contact Project Gutenberg of Australia go to http:\/\/gutenberg\.net\.au$/) {
            $state = 'end of aus header';
            $debug && print "state: aus header -> end of aus header\n";
        } elsif (/^A Project Gutenberg of Australia eBook$/) {
            $state = 'end of aus header';
            $debug && print "state: aus header -> end of aus header\n";
        }
    } elsif ($state eq 'end of aus header') {
        if (/^((Title|Author): .*)?$/) {
            # title, author, or blank line
        } else {
            $state = 'etext body';
            $debug && print "state: end of aus header -> etext body\n";
            $print = 1;
        }
    } elsif ($state eq 'etext body') {
        # here the stuff
        if (/^<!-- #INCLUDE virtual="\/include\/ga-books-textf\.html" -->$/) {
            $state = 'footer';
            $debug && print "state: etext body -> footer\n";
            $print = 0;
        } elsif (/^(\*\*\* ?)?end of (the )?project/i) {
            $state = 'footer';
            $debug && print "state: etext body -> footer\n";
            $print = 0;
        }
    } elsif ($state eq 'footer') {
        # nothing more of interest
    } else {
        die "unknown state '$state'";
    }

    if ($print) {
        print;
        ++$printed;
    } else {
        $debug && print "## $_";
    }
}

Ответ 3

Ничего себе, этот вопрос сейчас так стар. Тем не менее, пакет gutenbergr в R, похоже, делает хорошую работу по удалению заголовков, включая барахло после "официального" конца заголовка.

Сначала вам нужно установить R/Rstudio, затем

install.packages('gutenbergr')
library(gutenbergr)
t <- gutenberg_download('25519')  # give it the id number of the text

По умолчанию параметр strip_headers arg равен T. Вероятно, вы также захотите удалить иллюстрации:

library(data.table)
t <- as.data.table(t)  # I hate tibbles -- datatables are easier to work with
head(t)  # get the column names

# filter out lines that are illustrations and joins all lines with a space
# the \\[ searches for the [ character, the \\ are used to 'escape' the special [ character
# the !like() means find rows where the text column is not like the search string
no_il <- t[!like(text, '\\[Illustration'), 'text']
# collapse the text into a single character string
t_cln <- do.call(paste, c(no_il, collapse = ' '))