2014-08-31 91 views
0

在這個例子中,我想學習編寫自適應子程序的最佳方法。適應修剪子程序

我需要一個修剪文本的子程序(實際上,這是一個藉口,我的子程序可以做其他任何事情)。

爲了更靈活,我想我的子程序接受的參數不同的類型:

my @input = (' A ', ' B', 'C ');

  1. my @trimmed = trim(@input);

  2. trim(\@input);

  3. my $out = trim($input[0]);返回'A'

  4. trim(\$input[0]);修剪@input的第一個元素;

  5. trim(\@a, \@b, \@c);字符串中的每一個陣列被修整

  6. my $out = trim(\@a, ' A ', ' B'); $ OUT =(QW/A B /); (將要討論的行爲)

這裏是我目前的醜陋的解決方案:

sub trim { 
    state $re = qr/^\s+|\s+$/m; 
    my @a; 
    for(@_) { 
     if(ref eq 'SCALAR') { $$_ =~ s/$re//g; } 
     elsif(ref)   { trim(\$_) for(@$_); } 
     else    { push @a, s/$re//gr; } 
    } 
    return \@a if @a > 1; 
    return $a[0] if $a[0]; 
}  

是否有此實現支持不同類型的輸入如我上面提出的任何更好的解決方案?

這個問題的主要原因涉及我的最終應用程序,我在其中攜帶的文本可以存儲在字符串,字符串數組或甚至哈希中。

我想這是最好寫的:

trim(\@allmytexts); 
align(\@allmytexts, align=>'right'); 

比:

for(@allmytexts) { 
    trim($_); 
    align($_, align=>'right'); 
} 

回答

1

這個問題是題外話,並有可能很快關閉。

但是,「在這樣的子程序中詢問這種類型的行爲是否正確?」

我會說不。我很不清楚你希望這個子程序如何處理我面前的信息,而且在沒有提及你的文檔的情況下,我肯定會努力記住如果我沒有使用它一兩天。你會發現每個人都通過寫作來使用它

$string = trim($string) 

因爲這是他們記得的東西。

它也像你不清楚自己什麼一些呼叫做,因此

my $out = trim(\@a, ' A ', ' B'); $out = (qw/A B/); (behavior to be discussed) 

我懷疑你是用一種語言與不同的傳遞機制,而且這樣的事情將是有益的。在Perl中,的所有內容通過別名;因此對@_數組的元素的操作等同於實際參數上的相同操作。這意味着如果您將該值作爲參數傳遞,子例程可以修改任何可寫值。

考慮到這一點,傳遞一個參考以表明它將被就地修改只不過是一個標誌,指示子例程的行爲方式以及參考必須是的阻礙在可以使用之前解除引用。

問問你自己,你經常看到常用庫函數的行爲如何。例如,有獨立調用indexrindex做的非常類似的事情,並且現有的核心運營商lc合理類似於trim正在試圖做的,但它永遠只能接受一個參數,並返回轉換的結果。 sprintf可能被看作是printf的一個變體,如果只有它知道,如果文件句柄參數是對標量的引用,它應該將該字符串放入變量中,而不是將其寫入文件句柄。但它不是那樣設計的。

我只能提供一個替代解決方案來定義的問題。你不解釋真實生活中的困難,既然你不確定你自己應該做什麼,我懷疑是否有人能幫助你改善它。

還有一件事要問自己:返回值應該是什麼時候通過引用並且值被修改了?很明顯,它應該在修改後返回值,但是,由於您正在編寫自適應代碼,因此如何根據調用是在標量,列表還是無效上下文中更改返回值?或者,甚至更好,讓trimlvalue subroutine這樣就可以編寫類似

my $n = q{    999      }; 
++trim($n); 
+0

我同意。支持一種或兩種調用樣式 - 我建議'trim(\ $ inplace)'和/或'$ output = trim($ input)'。如果調用者需要修剪整個數組,Perl可以使用完美的'map'和'for'關鍵字。 – tobyink 2014-08-31 21:40:38

+0

@tobyink:正如我試圖暗示的,我不同意將傳遞引用作爲指示就地功能的標誌。或者像'trim($ string,inplace => 1)'或者'trim_inplace($ string)'就好了 – Borodin 2014-08-31 21:45:27

+0

@borodin,爲什麼你認爲我的問題是脫離主題? – nowox 2014-08-31 23:01:53

2

聽起來太複雜了我。用法比這更容易閱讀和記憶! [1]。只需要trim採取標量(默認爲$_)。

sub trim(_) { $_[0] =~ s/^\s+|\s+\z//rg } 

你所有的情況下,可以很容易地通過處理,從

​​

您可以就地版本太多。

sub trim_i(_) { s/^\s+|\s+\z//g for $_[0] } 

這將用於如下:

trim_i($x); 
trim_i for @a; 

另一種可能性是採取標量的列表(沒有默認值)。

sub trim { 
    wantarray 
     ? map s/^\s+|\s+\z//rg, @_ 
     : $_[0] =~ s/^\s+|\s+\z//rg 
} 

$x = trim($x); 
@a = trim(@a); 

sub trim_i { 
    s/^\s+|\s+\z//rg for @_; 
} 

trim_i($x); 
trim_i(@a); 

但它是一個有點奇怪。特別是因爲my $x = trim($y, $z);是可能的。


  1. 同時,它採用基於類型的多態性,這是不是在Perl是一個好主意。面對重載字符串化的對象時,您的代碼意外行爲。