Помогите преобразовать в подпрограмму - PullRequest
5 голосов
/ 15 июля 2011

Я попытался преобразовать свой код в серию подпрограмм, чтобы сделать его более модульным.Условные операторы в приведенном ниже коде - это то, что я не могу включить в подпрограмму.

next unless ( $sentblock =~ /\[sent. \d+ len. \d+\]: \[.+\]/ );               #1#
( $sentence, $sentencenumber ) = &sentence_sentnum_chptnum($sentblock); #SUBROUTINE
if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ ) {                                #2#
    $chapternumber = $1;
    $chapternumber =~ tr/./_/;
}
next
  unless ( $sentence =~ /\b\Q$search_key\E/i                                  #3#
    && $sentence =~ /\b\Q$addkey0\E/i
    && $sentence =~ /\b\Q$addkey1\E/i );
next
  if ( defined($exc0)                                                         #4#
    && length($exc0)
    && $sentence =~ /\b\Q$exc0\E\b/i );
next
  if ( defined($exc1)                                                         #5#
    && length($exc1)
    && $sentence =~ /\b\Q$exc1\E\b/i );

Подпрограмма до сих пор:

sub sentence_sentnum_chptnum {
    my $subsentblock = shift;
    my ( $subsentence, $subsentencenumber );
    return unless ( $subsentblock =~ /\[sent. (\d+) len. \d+\]: \[(.+)\]/ ); #DIDN'T replace the need to put one in the main script
    $subsentencenumber = $1;
    $subsentence       = $2;
    $subsentence =~ s/, / /g;
    return ( $subsentence, $subsentencenumber );
}

Она работает как есть, но если я попытаюсьпомещая другие условные выражения в: я получаю ошибки, говоря $sentence is uninitialized позже в коде.Пример: если я пытаюсь включить проверку $addkey, используя то же условие, но просто меняя next на return, я получаю сообщение об ошибке $sentence is uninitialized в строке: if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ ) { И аналогично, если я ставлю любое изэти условия в подпрограмме.

Главный вопрос: Как я могу:

(1) избавиться от next unless ( $sentblock =~ /\[sent. \d+ len. \d+\]: \[.+\]/ ); (это тоже в подпрограмме)

(2) Включить: if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ ) & все 3 next заявления

(3) Поскольку оно включено, также вернуть $chapternumber

Не затрагивая мой код?

Общий вопрос передового опыта: Если у меня есть переменные, определенные в верхней части моего кода (из HTML-формы), лучше практиковать их локализацию каждый раз в каждой подпрограмме или просто не передавать ничего вподпрограмму, и использовать значение, назначенное в начале кода?(Пример. $search_key, $addkey и $exc)?

Контрольный пример Я создал контрольный пример, однако он довольно длинный, поэтому я его не включал,Если вам это нужно, это очень похоже на: http://perlmonks.org/?node_id=912276 просто найдите, где подпрограмма вступает во владение, и удалите эту часть ... Это сразу после foreach my $sentblock (@parsed).

Примечание: контрольный пример не включает addkey или exc, и ничто не будет соответствовать номеру главы (поместите '~ 5.5' перед одним предложением, чтобы включить его)

Я пытался проверять возвращенные $sentence в основной программе.Это устраняет ошибку, но нет совпадений для остальной части программы (т. Е. Конечный результат поисковой системы равен 0).

Спасибо, дайте мне знать, если что-то неясно.

Ответы [ 2 ]

3 голосов
/ 16 июля 2011

Сколько вы хотите сломать вещи? Трудно понять, какой «лучший» или «правильный» способ разделить вещи без кода.

В общем, если вы просматриваете свой код и добавляете комментарии, описывающие, что делает каждый блок кода, вы можете с такой же готовностью заменить каждый закомментированный блок подпунктом, имя которого повторяет предложение:

# Is this a sentence block?
next unless ( $sent_block =~ /\[sent. \d+ len. \d+\]: \[.+\]/ );    
           #1#

my ( $sentence, $sentence_number ) = parse_sentence_block($sent_block);

# Get chapter info if present
if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ ) {                                #2#
    $chapter_number = $1;
    $chapter_number =~ tr/./_/;
}

# Skip if key found
next
  unless ( $sentence =~ /\b\Q$search_key\E/i                                  #3#
    && $sentence =~ /\b\Q$addkey0\E/i
    && $sentence =~ /\b\Q$addkey1\E/i );

# skip if excrescence 0 (or whatever exc is short for)
next
  if ( defined($exc0)                                                         #4#
    && length($exc0)
    && $sentence =~ /\b\Q$exc0\E\b/i );
# skip if excrescence 1.
next
  if ( defined($exc1)                                                         #5#
    && length($exc1)
    && $sentence =~ /\b\Q$exc1\E\b/i );

Теперь возьмите эти комментарии и превратите их в сабвуферы:

next unless is_sentence_block( $sent_block );

my( $sentence, $sentence_number ) = parse_sentence_block($sent_block);

# Maybe update the chapter number
my $new_chapter_number = get_chapter_number( $sentence );
$chapter_number = $new_chapter_number if defined $new_chapter_number;

next unless have_all_keys( $sentence => $search_key, $add_key0, $add_key1 ); 

next if have_excrescence( $exc0 );
next if have_excrescence( $exc1 );


sub is_sentence_block {
    my $block = shift;

    return $sent_block =~ /\[sent. \d+ len. \d+\]: \[.+\]/ );
}

sub get_chapter_number {
    my $sentence = shift;

    return unless $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/;
    return $1;
}

sub have_all_keys {
     my $sentence = shift;
     my @keys = @_;

     for my $key ( @keys ) { 
         return unless $sentence =~ /\b\Q$key1\E/i;
     }

     return 1
}

sub have_excrescence {
    my $sentence = shift;
    my $exc      = shift;

    return 0 unless defined($exc);
    return 0 unless length($exc)
    return 0 unless $sentence =~ /\b\Q$exc\E\b/i );

    return 1;
}
1 голос
/ 16 июля 2011

Попробуйте этот подход (часть этого кода может показаться вам знакомой ;-)):

sub extractSentenceAndPositions {
    my $sentenceBlock = shift;
    my ($sentence, $sentenceNumber, $chapterNumber) = ("", "", "");

    if ($sentenceBlock =~ /\[sent. (\d+) len. \d+\]: \[(.+)\]/) {
        $sentenceNumber =  $1;
        $sentence       =  $2;
        $sentence       =~ s/, / /g;

        if ($sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/) {                                   #2#
            $chapterNumber  =  $1;
            $chapterNumber  =~ tr/./_/;
        }

        # Turning the original 'next-unless' chain into a conditional
        # which zeroes out the return values instead
        if ( !( $sentence =~ /\b\Q$search_key\E/i                                      #3#
             && $sentence =~ /\b\Q$addkey0\E/i
             && $sentence =~ /\b\Q$addkey1\E/i )
            ||
             !( defined($exc0)                                                         #4#
             && length($exc0)
             && $sentence =~ /\b\Q$exc0\E\b/i )
            ||
             !( defined($exc1)                                                         #5#
             && length($exc1)
             && $sentence =~ /\b\Q$exc1\E\b/i )
           ) {
               ($sentence, $sentenceNumber, $chapterNumber) = ("", "", "");
        }
    }  

    return ($sentence, $sentenceNumber, $chapterNumber);
}

Затем замените свой первый список на ...

($sentence, $sentenceNumber, $chapterNumber) = extractSentenceAndPositions($sentblock);
next if (!$sentence || !$sentenceNumber || !$chapterNumber);

Что касается вопроса о наилучшей практике, я бы сказал, что для этого варианта использования (cgi vars и т. П.), Где эти значения почти наверняка не изменятся, я бы обратился к ним напрямую. Основная концепция, которой я обычно придерживаюсь, состоит в том, чтобы очистить их один раз в начале цикла (под этим я подразумеваю очистку от любых SQL-инъекций, XSS, XSRF, инъекций оболочки или других подобных мерзостей в значениях) и с тех пор трактовать их как глобалы только для чтения. Я слышал другие мнения по этому вопросу, но я обычно так и делаю.

Что касается проверки возвращенного $sentence в основной программе, каким-то образом уничтожающего все остальные совпадения, я не уверен, как это произойдет, если не произойдет что-то еще. Я использовал этот подход (next или last на основе возвращаемых значений) во многих сценариях, и в этом нет ничего разрушительного по своей сути.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...