Perl字符串与排序

用index查找子字符串

找出子字符串在主字符串中的相对位置,而且是首次出现的地方,返回值从0开始,如果没找到,则返回-1.还可以加上第三个参数,来指定开始搜索的地方。

$where = index($big,$small);
my $stuff = "Howdy world!";
my $where1 = index($stuff,"w");   =>2
my $where2 = index($stuff,"w",$where1+1);   =>6
my $where3 = index($stuff,"w",$where2+1);   =>-1

有时候你可能需要搜索子字符串最后出现的位置,可以用rindex函数,它会从字符串末尾的地方开始找起。它也可以加上第三个参数,来指定返回值的上限。

my $fred = "yabba dabba doo!";
my $where1 = index($fred ,"abba");   =>7
my $where2 = index($stuff,"w",$where1-1);   =>1
my $where3 = index($stuff,"w",$where2-1);   =>-1

用substr操作子字符串

返回目标串从指定位置开始的指定长度的子串,如果长度超过了字符串的长度,perl会一直取到结尾。如果你真的就是打算从某个位置开始取到字符串的结尾,那么省略第三个参数就好了。substr还可以有第四个参数,用来将找到的字符串替换成指定字符串,返回值是替换前的子串。

my $part = substr($string , $initial_position,$length);
my $previous_value = substr($string,0,5,"goodbye");

sprintf格式化字符串

sprintf跟printf功能类似,但它不是打印所请求的字符串,而是返回它,可以将返回结果存到变量里供程序使用。

my $date_tag = sprintf "%4d/%02d%02d %2d:%02d:%02d"

来看一个例子,将12345678.899转化成12,345,678.90。

sub big_money{
    my $number = sprintf "%.2f",shift @_;
    while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
    $number =~ s/^(-?)/$1\$/;
    $number;
    }

注意while修饰符的用法,它没有循环体,只有循环条件,其实这条语句的目的就是执行条件表达式(替换运算),而不是无用的循环主体。

将非十进制数字字符串转换成十进制数字

hex("0xDEADBEEF"); 16进制=>10进制
oct("0377");       8进制=>10进制
oct("0b1101");     2进制=>10进制

高级排序

在某些情况下,你可能需要将数组元素按照你的要求来排序,例如数字字符串'101'应该大于'99',而如果按照字符串的排序规则,'101'会小于'99';又比如你或许需要进行不区分大小写的字符串排序。这时,你需要自己写定制的排序子程序。

sub by_number{
if($a < $b){-1}elsif($a > $b){1}else{0}
}
my @result = sort by_number @sum_numbers;

请注意,在排序子程序里,我们不需要声明\$a,\$b,因为perl已经帮我们做好了。并且perl还提供了<=>和cmp操作符来简写数字和字符串的比较。

sub by_number{
$a <=> $b;
}

sub case_insensitive{
"\L$a" cmp "\L$b";
}

注意在比较的时候,我们并没有修改被比较元素的值,而只是用他们的值做一些变换进行比较而已,这一点很重要:\$a,\$b并非数据项的拷贝,实际上它们只是原始列表元素的临时别名,所以千万别去修改他们的值,否则就会弄乱原始数据。 更简单的写法是,直接将排序子程序内嵌到排序子程序名的位置就行了。

my @numbers = sort {$a <=> $b} @some_numbers;

注意比较操作符<=>和cmp是短视的,也就是说,它并不知道哪个操作数是\$a,哪个是\$b,它只知道哪个在左边,哪个在右边,因此下面的两个语句完成了一样的功能。

my @numbers = sort {$b <=> $a} @some_numbers;
my @numbers = reverse sort {$a <=> $b} @some_numbers;

按hash值排序

有的时候,我们希望按照hash的值来对hash表排序。想象一下,我们有下面一个例子.

my %score = ("barney" => 195,"fred" => 205,"dino" => 30);
my @winners = sort by_score keys %score;
sub by_score {
    $score{$b} <=> $score{$a}
}

我们将\$b放在\$a之前,可以达到降序排列的目的。

按多个键排序

如果两个键的值相同,此时,我们希望按照键的ASCII码返回。

sub by_socre and name{
    $score{$b} <=> $score{$a}
        or
    $a <=> $b
}
my @winners = sort by_score keys %score;

上面的程序利用了or操作符的短路特性。

Comments !