1. 程式人生 > >Perl字串與排序

Perl字串與排序

Perl字串與排序

1. 字串操作函式

1.1 index() 字串查詢函式

  • index 可以用於查詢給定的字串a是否出現在某個字串b中,其實就是找到a在b中出現的位置;
  • 找到匹配字元返回index,否則返回-1;
    • 用法1: index($str1,$str2)
    • 含義:查詢 $str2 在 $str1 中出現的位置,從字串首位開始查詢;
    • 用法2: index($str1,$str2,$number)
    • 含義:查詢 $str2 在 $str1 中出現的位置,$number為查詢到起始位置,限制返回的最小值;
#!/usr/bin/perl
my $stuff = "Hello, world world";
my $where = index($stuff,"wor");             # $where=7,因為H的索引為0,所以world中w的索引值為7
my $where1 = index($stuff,"wor",$where+1);   # $where=7,因為索引的起始位置是8,所以第二個world中w的索引值為13
my $where2 = index($stuff,"wor",$where1+1);  # $where=14,未找到匹配字串,返回 -1
# 迴圈查詢
my
$stuff = "Hello, world world"; my @where = (); my $where = -1; while (1) { $where = index($stuff,"wor",$where+1); last if $where == -1; push @where,$where; } say "Positions are @where";
  • rindex 可以用於查詢給定的字串a是否出現在某個字串b中,反向查詢,從字串的末尾開始查詢;
    • 用法1: rindex($str1,$str2)
    • 含義:查詢 $str2 在 $str1 中出現的位置,從字串末尾開始;
    • 用法2: rindex($str1,$str2,$number)
    • 含義:查詢 $str2 在 $str1 中出現的位置,$number為查詢到起始位置,$numner限制了返回的最大值;
#!/usr/bin/perl
my $stuff = "yabba dabba doo";
my $where = rindex($stuff,"abba");               # $where=7,
my $where1 = rindex($stuff,"abba",$where-1);     # $where=1,因為索引的起始位置是6,向前匹配
my $where2 = rindex($stuff,"abba",$where1-1);    # $where=-1,起始查詢位置為0,未找到匹配字串,返回 -1
# 迴圈查詢
my $stuff = "yabba dabba doo";
my @where = ();
my $where = length $stuff;                       # 通過length函式返回
while (1) {
	$where = index($stuff,"abba",$where-1);
	last if $where == -1;
	push @where,$where;
}
say "Positions are @where";

1.2 substr() 操作子字串

  • substr可以用於處理較長字串中的一小部分:子字串提取
  • 返回指定位置的子字串。
    • 用法1: substr ($string,$initial_position,$length)
    • 含義:從$initial_position位置開始查詢,取出$length長度的字串;如果$initial_position為負值,表示從字串結尾的倒數第三個字元開始處理,(最後一個字串為-1),取出對應長度的字串;
    • 用法2: substr ($string,$initial_position)
    • 含義:如果第三個引數省略,代表取回$string中從$initial_position位置至末尾的所有字元;
#!/usr/bin/perl
my $stuff = "yabba dabba doo";
my $sub = substr($stuff,3,2);                 # $sub="ba"
my $sub = substr($stuff,7);                   #取回從7開始的所有字串 $sub="abba doo"
my $sub = substr($stuff,-3,2);                # $sub="do"
my $sub = substr($stuff,-5);                  #取回從-5開始的所有字串 $sub="a doo"
my $sub = substr($stuff,index($stuff,"o"));   #和index的聯合使用,取回從字元“o”開始的所有字元,$sub="oo"
  • substr可以用於處理較長字串中的一小部分:子字串插入/替換/刪除
#!/usr/bin/perl
my $stuff = "yabba dabba doo";
substr($stuff,0,5) = "Goodbye";     # $stuff="Goodbye dabba doo",移除從0開始的5個字元,並插入新的字串
substr($stuff,8,0) = "abc ";        #第三個引數為零,不移除任何內容只插入,$stuff="Goodbye abc dabba doo"
substr($stuff,-15) =~ s/abc/xyz/;   #只處理最後的20個字元,$stuff="Goodbye xyz dabba doo"
#使用傳統的四個引數方法呼叫
substr($stuff,0,5,"Goodbye");       # $stuff="Goodbyeye xyz dabba doo",移除從0開始的5個字元,並插入新的字串

1.3 sprintf() 格式化字串

  • sprintf 和 printf 具有相同的引數,但是返回的是結果字串,而不會直接打印出來。
  • 可以將格式化後的字串存放在變數中,以備後續使用。
#!/usr/bin/perl
my $data_tag = sprintf 
   "%4d/%02d/%02d %2d:%02d:%02d",
   $yr,$mon,$day,$h,$min,$sec;      #可能得到:2018/01/19 3:00:08 這種類似的結果
my $money = 123456789.0456;
my $mon = sprintf "%.2f",$money;    #$mon = 123456789.05, 進行數字處理
  • %nd 中 n 表示輸出位寬為n,如果輸出格式小於 n 用空格在左邊補齊;
  • %0nd中 n 表示輸出位寬為n,如果輸出格式小於 n 用0在左邊補齊;

2. 高階排序

2.1 排序規則子程式

Perl 允許使用者建立自定義的排序規則子程式,用於解釋具體的排序規則;
Perl 知道如何進行列表的排序,依次比較列表中的兩個數字,然後按照順序排列,Perl已經幫我們做好了這些,我們只需要告訴Perl如何比較兩個數字即可,Perl會幫助我們完成其他的處理。

  • 排序子程式和定義和普通子程式的定義基本一致,他會被反覆呼叫,每次都檢查列表中的兩個元素
#!/usr/bin/perl
sub any_sort {           # 實際上這麼寫不能正確工作,這裡只是為了方便說明問題
	my ($a,$b) = @_;     # 宣告兩個變數並給他們賦值
	#進行$a $b的比較    
	...
}

也許宣告一次 $a,$b並賦值不會耗費多少時間,但是當子程式被呼叫成千上萬次的話,這些時間將會嚴重影響程式的處理速度。因此我們不需要這麼做,Perl已經為我們做好了,$a 和 $b將會是來自原始列表的元素,沒有對他們進行宣告和賦值,他們不過是列表中的原始元素在子程式中的別名而已,因此對$a和$b的操作是會改變原始列表中的值的,因此這裡應該十分注意,儘量不要修改這兩個變數的值。

  • 如果在變數列表中$a應該排在$b的前面,排序子程式返回 -1;
  • 如果在變數列表中$a應該排在$b的後面,排序子程式返回 1;
  • 如果在變數列表中$a和$b的值相等,排序子程式返回 0;
#!/usr/bin/perl
sub by_number {
	if ($a<$b) {-1} elsif ($b>$a) {1} else {0}    #我們不需要宣告$a和$b,我們只需要之處他們的比較規則
}
#排序子程式的呼叫
my @results = sort by_number @some_number;
  • 其實,perl為我們定義了數字和字串的三路比較符 <=> cmp
    • 如果$a $b是數字,$a <=> $b 的比較結果
    • $a<$b 返回 -1,$a=$b 返回0,$a>$b 返回1
    • 如果$a $b是字串,$a cmp $b 的比較結果
    • $a lt $b 返回 -1,$a eq $b 返回0, $a lt $b 返回1

現在我們可以使用 <=> 進行排序了:

#!/usr/bin/perl
my @results = sort {$a <=> $b}  @some_number;           #使用花括號將$a $b的比較規則括起來
my @results = reverse sort {$a <=> $b}  @some_number;   #使用reverse進行倒序排序
my @results = sort {$b <=> $a}  @some_number;           #不適用reverse進行倒序排序

第三行排序語法中,我們將$a 和 $b 對換位置,就可以實現倒序排序,因為<=>和cmp時段是的,他們並不知道那個是a哪個是b,只知道左右,所以我們如果把$a和$b對調,比較操作就會得到相反的結果。

2.2 按照雜湊值進行排序

#!/usr/bin/perl
my %score = (
	"barney" => 87,
	"fred"   => 96,
	"dino"   => 78,
);
my @winner = sort by_score keys %score;     #採用by_score的機制進行排序,對得到的keys按照其value進行排序
sub by_score { $score{$b} <=> $score{$a}}   #不適用$a和$b,改為使用其對應的雜湊值進行比較,a和b交換位置,表示數字較大的排在前面,降序排列
print @winner\n;                            #結果:fred barney dino

2.3 按多個鍵進行排序

#!/usr/bin/perl
# 兩級排序
my %score = (
	"barney" => 87,
	"fred"   => 96,
	"dino"   => 78,
	"aock"   => 78,
);
my @winner = sort by_score_and_name keys %score;     #採用by_score的機制進行排序,對得到的keys按照其value進行排序
sub by_score_and_name { 
	$score{$b} <=> $score{$a}      #先按照分數進行排列
	or
	$a cmp $b                      #如果分數相同,按照名稱進行排序
} 
print @winner\n;                            #結果:fred barney aock dino
  • 當然,除了兩級排序,我們還可以進行多級排序,例如圖書館對借閱者編號ID進行五級排序,五個等級分別是未交罰金$fines, 目前借閱書本數目 $number, 姓名$name, 先按照family_name排序,再按照personal_name排序,最後是借閱者的ID,以防止前面的資訊都相同;
#!/usr/bin/perl
@patron_IDs = sort {
	$fines{$b}    <=>   $fines{$a}  or         #數字標量使用 <=> ,降序排列
	$number{$b}   <=>   $number{$a} or
	$family{$b}   cmp   $family{$a} or         #字串標量使用 cmp,降序排列
	$person{$b}   cmp   $person{$a} or
	$a <=> $b;                                 #ID按照升序排列
} @partron_ID