帮助转换为子程序

时间:2011-07-15 16:17:37

标签: perl

我试图将我的代码转换为一系列子程序,使其更加模块化。下面代码中的条件语句是我无法合并到子例程中的。

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收到错误:{{ 1}}同样,如果我将任何这些条件放入子程序中。

主要问题:我该怎么做:

(1)摆脱if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ ) {(它也在子程序中)

(2)包括:next unless ( $sentblock =~ /\[sent. \d+ len. \d+\]: \[.+\]/ );&所有3 if ( $sentence =~ /\~\s(\d*F*[\.I_]\w+)\s/ )个陈述

(3)既然包括它,也返回next

不影响我的代码?

一般最佳实践问题:如果我在代码顶部定义了变量(来自HTML表单),那么每次在每个子程序中对它们进行本地化或者不传递任何内容都是更好的做法。进入子程序,并使用代码开头指定的值? (例如$chapternumber$search_key$addkey)?

测试用例我做了一个测试用例,但它很长,所以我没有包含它。如果你需要一个,它非常类似于:http://perlmonks.org/?node_id=912276只需查找子程序接管的位置并删除该部分......它就在$exc之后。

注意:测试用例不包括foreach my $sentblock (@parsed)addkey,并且没有任何内容符合章节编号(在一个句子前面加上'~5.5'以包含它)

我已尝试检查主程序中返回的exc。这消除了错误,但是程序的其余部分没有匹配(即搜索引擎的最终结果是0结果)。

谢谢,如果有什么不清楚,请告诉我。

2 个答案:

答案 0 :(得分:3)

你想要打破多少钱?很难看出分离的“最佳”或“正确”方式是没有更多代码。

一般情况下,如果您浏览代码并添加描述每个代码块所做内容的注释,您可以使用名称可以重述句子的sub替换每个注释块:

# 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 :(得分:1)

尝试这种方法(这些代码可能看起来很熟悉;-)):

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,shell注入或值中的其他此类肮脏)并从那时起将它们视为只读全局变量。我听过关于这个问题的其他意见,但这就是我通常做的事情。

至于检查主程序中返回的$sentence以某种方式破坏所有其他匹配,我不确定除非还有其他事情发生,否则会发生这种情况。我在很多脚本中都使用过这种方法(基于返回值的nextlast),并没有任何内在的破坏性。