Глагола парсер


Я написал этот код на Perl, и еще больше добавить, но я надеялся, что я мог бы получить некоторые мнения о том, является ли это могло быть написано лучше.

В частности, есть центральная если-elsif операторы структура. Я должен сделать эту функцию или нет? Что лучше практики?

Кроме того, посмотрите на 2-й блок кода, и дайте мне знать, если это стоит того, чтобы изменить эту подпрограммы (либо поместить весь Если-нибудь в суб, или только внутренняя часть).

Вообще, мне просто интересно, если есть некоторые лучшие трюки, чтобы получить ту же работу. Возможно, используя массив хэшей, а не массив массивов? Для облегчения чтения. Бы это предотвратить экв играм от появления?

Во-первых, заявления:

#!/usr/bin/perl

use strict;
use warnings FATAL => "all";
require 'verbTenseChanger.pl';

## -JUST FOR TESTING- ##
my $chapter_section = "chpt"."31_4";
my $search_key = "move";
my $category_id = "all";

# --- Files --- #
open(my $parse_corpus, '<', "parsed${chapter_section}.txt") or die $!;

# --- Different forms of the Searchword --- #
my @temp_changeverbforms = map changeVerbForm( $search_key, 0, $_ ), 1..4;
my @verbforms;
push (@verbforms, $search_key);# Watch extra for loop
foreach my $temp_changeverbforms (@temp_changeverbforms) {
    push (@verbforms, $temp_changeverbforms) unless ($temp_changeverbforms eq "");
}

# --- Variables for required info from parser --- #
my @entirechapter = <$parse_corpus>;
my $chapternumber;
my $sentencenumber;
my $sentence;
my $grammar_relation;
my $argument1;
my $argument2;
my @all_matches;

my $entirechapter = join ('',@entirechapter); ##Flatten file (make one big string)

#To get each sent. and info in one string:
my @sentblocks = split (/Parsing\s/,$entirechapter);##Remove "Parsing" which is on the line of the chptnumber
$chapternumber = $sentblocks[1]; ## file: chpt... will always be at [1]

# --- Retrieve necessary info from text --- #

#Loop through all the sentences, and for each check every form of searchverb
foreach my $sentblock (@sentblocks) {
    foreach my $verbform (@verbforms) { 
        ##"next" skips to next iteration of loop, substitute for an over-arching if statement
        next unless ($sentblock =~ /\b$verbform\b/i); ##Ensure the sentence contains the searchkey
        next unless ($sentblock =~ /\(VB\w*\s+\b$verbform\b\)\s+/i); ##Ensure searchkey is a verb
        #Sent.number and Sentence:
        next unless ($sentblock =~ /\[(sent. \d+) len. \d+\]: \[(.+)\]/); ##Remember, talking about the whole block here
        $sentencenumber = $1;
        $sentence = $2;
        $sentence =~ s/, / /g;

Вот если-elsif операторы , которые могут или не могут быть преобразованы в подпрограммы:

        #Dependencies (relations and arguments):
        if ($category_id eq "all") {
            my @lines = split ("\n",$sentblock); ##Split by a newline
            foreach my $line (@lines) {
                my @matches;
                next unless ($line =~ /\b$verbform\b/i); ##Ensure dependency contains searchword
                            ##NEXT LINE IS DIFFERENCE:
                next unless ($line =~ /subj\w*\(|obj\w*\(|prep\w*\(|xcomp\w*\(|agent\w*\(|purpcl\w*\(|conj_and\w*\(/); ##Ensure dependency only contains desired grammar relations
                next unless ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/); ##Ensure dependency is a dependency AND get info from it
                $grammar_relation = $1;
                $argument1 = $2;
                $argument2 = $3;

                next if ($argument1 eq $argument2); ##Ensure 1st and 2nd argument aren't the same
                next if ($grammar_relation =~ /xcomp/i and $argument2 !~ /\b$verbform\b/i); ##Ensure for xcomp the searchword is the 2nd argument
                next if ($argument1 =~ /^\S$/ or $argument2 =~ /^\S$/); ##Exclude if argument is only 1 character

                push(@matches, $chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2); ##All here, so either all get pushed or none (no holes in array)
                push @all_matches, \@matches;
            }
        }
        elsif ($category_id eq "subj") {
            my @lines = split ("\n",$sentblock); ##Split by a newline
            foreach my $line (@lines) {
                my @matches;
                next unless ($line =~ /\b$verbform\b/i); ##Ensure dependency contains searchword
                next unless ($line =~ /subj\w*\(|agent\w*\(/); ##Ensure dependency only contains desired grammar relations
                next unless ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/); ##Ensure dependency is a dependency AND get info from it
                $grammar_relation = $1;
                $argument1 = $2;
                $argument2 = $3;

                next if ($argument1 eq $argument2); ##Ensure 1st and 2nd argument aren't the same
                next if ($argument1 =~ /^\S$/ or $argument2 =~ /^\S$/); ##Exclude if argument is only 1 character

                push(@matches, $chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2);
                push @all_matches, \@matches;
            }
        }
        elsif ($category_id eq "xcomp") {
            my @lines = split ("\n",$sentblock); ##Split by a newline
            foreach my $line (@lines) {
                my @matches;
                next unless ($line =~ /\b$verbform\b/i); ##Ensure dependency contains searchword
                next unless ($line =~ /xcomp\w*\(|conj_and\w*\(|prep_by\w*\(|purpcl\w*\(/); ##Ensure dependency only contains desired grammar relations
                next unless ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/); ##Ensure dependency is a dependency AND get info from it
                $grammar_relation = $1;
                $argument1 = $2;
                $argument2 = $3;

                next if ($argument1 eq $argument2); ##Ensure 1st and 2nd argument aren't the same
                next if ($grammar_relation =~ /xcomp/i and $argument2 !~ /\b$verbform\b/i); ##Ensure for xcomp the searchword is the 2nd argument
                next if ($argument1 =~ /^\S$/ or $argument2 =~ /^\S$/); ##Exclude if argument is only 1 character

                push(@matches, $chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2);
                push @all_matches, \@matches;
            }
        }
        elsif ($category_id eq "obj" or $category_id eq "prep") {
            my @lines = split ("\n",$sentblock); ##Split by a newline
            foreach my $line (@lines) {
                my @matches;
                next unless ($line =~ /\b$verbform\b/i); ##Ensure dependency contains searchword
                next unless ($line =~ /$category_id\w*\(/); ##Ensure dependency only contains desired grammar relations
                next unless ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/); ##Ensure dependency is a dependency AND get info from it
                $grammar_relation = $1;
                $argument1 = $2;
                $argument2 = $3;

                next if ($argument1 eq $argument2); ##Ensure 1st and 2nd argument aren't the same
                next if ($argument1 =~ /^\S$/ or $argument2 =~ /^\S$/); ##Exclude if argument is only 1 character

                push(@matches, $chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2);
                push @all_matches, \@matches;
            }
        }
    }
}

#To make the if elsif into subroutine: Name:get_all_matches  Pass In: ($sentblock, $verbform, $chapternumber, $sentencenumber, $sentence) Return:  @allmatches (if needed, return reference)

А затем в печати:

# --- Loop through all Matches --- #

for my $arrayref (@all_matches) { 
    #for my $item (@$arrayref) { 
        print @$arrayref, "\n\n\n";
    #}
}
#Sort by what?? 1.grammar_relation 2.arguments 3.alphabetical
#But how to print heading only once? use hash?
# How to sort by frequency (ie. sort by the number sentences with the same grammar_relation AND arg1 AND arg2)

Вы можете игнорировать замечания последнего, или дать мне некоторые указатели бонус от опыта. Позже, мне нужно отсортировать результаты. Бы сортировку сделать до этого последнего шага?

Вот формат, если вы действительно склонны на понимание кода:

Парсинг файла: chpt31_4.txt

Парсинг [послал. 15 лен. 9]: [этих животных, двигаться, медленно, или, не, в, все .]

(Корень

(НП (ДТ эти) (ННС животных))
(ВП (ВБП двигаться)
(ADVP (медленно РБ)
(КС или)
(Не РБ))
(ADVP (в) (ДТ всех)))
(. .)))

дет(животные-2, к-1)
nsubj(Шаг-3 животные-2)
advmod(перемещаться-3, медленно-4)
advmod(перемещаться-3, нет-6)
conj_or(медленно-4, нет-6)
advmod(перемещаться-3, АТ-7)
pobj ПО(в-7, всего-8)



247
3
задан 11 июня 2011 в 05:06 Источник Поделиться
Комментарии
2 ответа

Вы, сэр, нужна стратегия шаблон-по крайней мере решить ваши если->для elseif проблема. Я нахожу Банда четырех стиль ссылка http://www.blackwasp.co.uk/Strategy.aspx чтобы быть немного легче на мозг для первого потребления нового образца, чем на Perl глубокое погружение, но YMMV.

2
ответ дан 12 июня 2011 в 12:06 Источник Поделиться

Меньше табличных переменных делает код намного более читабельным:

# --- Loop through all Matches --- #
print @{$_}, "\n\n\n" for @all_matches;

Выпуск карты является массивом. Научиться массива-вывод цепочки функций в другой массив-вывода функции для дальнейшего снижения темп ВАР беспорядок:

# --- Different forms of the Searchword --- #
my @verbforms = (
$search_key,
(
grep { $_ ne '' }
map { changeVerbForm( $search_key, 0, $_ ) } (1..4);
)
);

Увидеть преобразование Шварца для наиболее часто используемых идиом этой идеи.

Использовать || и &&, чтобы уменьшить количество заявлений:

next if $arg1 eq $arg2 || $arg1 =~ /^\S$/ || $arg2 =~ /^\S$/;

Я чувствую, что тернарные операторы могут также обслуживать вас хорошо, но у меня нет времени!

2
ответ дан 15 июня 2011 в 06:06 Источник Поделиться