zoukankan      html  css  js  c++  java
  • 《Perl语言入门》学习笔记

    0.前言

    本文主要是记录perl学习中的一些关键知识点,尽可能帮助平日的脚本开发需要
    

    1.标量数据

    a 数字

    perl内部对数字,统一都是按照双精度浮点数double类型来存储的,
    

    b 字符串

    最短的字符串是不含任何字符的空串,最长的字符串没有限制
    
    字符串相关操作
    • 分割:使用的是split函数,split /,/ $str 等价于split(/,/, $str),返回的是数组
    • 连接:字符串的连接使用的是符号.来进行,例如 $newStr=$a . " " . $b;
    • 重复:例如需要得到abcabcabc,那么可以根据字符串进行这样的操作 "abc" x 3
    • 子串:substr()获取子串,substr(字符串,开始的索引位置,长度,替换的字符串)
    • 长度:length()返回
    • 比较:字符串的比较用的是eq ne

    perl中的字符串和数字会自动转换,具体情况是看使用了什么操作符

    数字的飞碟操作符

    a <=> b 表示对数字a和数字b进行比较,返回-1,0,1三种结果

    2.变量

    变量的类型主要是有这么几种

    • 标量:$a = 1
    • 数组: @a = (1, 2, 3)
    • hash: %a = ('a' => 0, 'b' => 1, 'c' => 2)

    perl的三种变量是存在不同的命名空间里,所以 $a, @a, %a 三者是不冲突的。但我们应该避免这样命名,可读性还是很糟糕的。

    字符串标量内插

    被双引号包裹的字符串,可以使用变量内插,这个和linux shell中的一样,例
    "hello $name" 等价于 'hello' . $name

    3.控制结构

    if

    这个与java中的一样,唯一不同的是,逻辑判断可以使用 and, not, or, xor, 还有 ne, eq 等等
    值得注意的是,与js一样,if对不同类型的变量的布尔值处理也是有规律的

    • 0 false, 其他数值都是true
    • 值为字符串,空字符串是假,其他有长度的为真
    • 既不是数字,也不是字符串,就会先试图转换为数字或者字符串
    unless

    unless 等于 if ( not xxxx) 这个样子

    unless (a == 1) {
    	# do something
    }
    
    elsif

    等于java中的else if

    获取行输入

    获取用户的行输入,使用的是句柄<STDIN>,返回一个字符串,并且一般最后带有一个换行符。

    $ilne=<STDIN>;
    if ($line eq "
    ") {
    	print "That was just a blank line!
    ";
    } else {
    	print "That line of input was $line";
    }
    
    chomp

    只能用于字符串变量上,仅把换行符去掉

    while

    与java一样,真假值得判断和if中的一样

    循环体中的几种控制符
    last

    等于break

    next

    等于continue

    带标签的块

    perl中建议使用大写来作为标签名,标签的使用时 标签名+冒号

    LINE: while(<>) {
    	foreach (split) {
    		last LINE if /__END__/;
    	}
    }
    

    三目运算符

    my $size = 
    	($width <10 ) ? "small" :
    	($width <20 ) ? "medium" :
    	($width <30 ) ? "large" :
    		"extra-large";			#default
    
    undef

    如果没有赋值某个变量,那这个变量的的初始值是undef
    - 当被作为数字使用时,为0
    - 当被当做是字符串使用时,是空串

    defined函数

    该函数可以区分undef和空串,例如在读取文件的时候,当eof了,则会返回undef回来,这个时候就可以通过这个来判断了

    $madona=<STDIN>;
    if (defined($madona)) {
    	print "the input is $madona";
    } else {
    	print "the input is empty
    ";
    }
    

    4.列表与数组

    数组下标从0开始,以此类推,最后一个元素的下标是-1。

    列表直接量

    需要引入列表的时候可以写成数组的样子,在圆括号中用逗号隔开的一系列值

    (1,2,3)
    ("a","b",1)
    (1..100)
    
    qw

    如果只是建立简单的单词列表,那么许多乏味的双引号和逗号会惹人讨厌。perl提供了qw的写法来简化
    qw( a b c d e )

    qw=quoted word,译为加上引号的单词,不论如何,perl会将里面当做是字符串来处理,qw的边界符不仅仅是括号,基本上成对出现的字符就行

    qw ! a b c !
    qw / a b c /
    qw # a b c #
    qw < a b c >
    

    以上的几种写法都是合法的

    列表赋值

    ( $a, $b, $c ) = ("111", "222", "333")
    左侧列表中的三个变量,依次会赋予右侧列表的值

    push pop shift unshift

    push和pop对对数组的最后一个元素来进行操作

    @arr=1..3
    @brr=5..7
    push(@arr, "1")
    push @arr,@brr;  # @arr得到@brr数组的所有元素
    pop(@arr)
    

    shift与unshift刚好相反,是对第一个元素来进行操作的

    shift(@arr)			# 弹出第一个元素
    unshift(@arr,"1")	# 将1添加到第一个位置
    

    foreach

    示例,每次循环迭代的时候,里面的控制变量是数组中的元素本身,任何修改都可以反映到本身。

    @rocks=qw / 1 2 3 4 /
    foreach $rock (@rocks) {
    	$rock = "	$rock";  
    	$rock .= "
    ";
    }
    

    如果我们没有指定控制变量,那么会被默认存在$_

    foreach (1..10) {
    	print "current number $_"
    }
    

    reverse sort

    sort可以指定比较规则,比较规则是一个函数

    sub by_ascii {
    	$a cmp $b;
    }
    my @strings = sort by_ascii @any_strings;
    

    5.子程序

    子程序更像是我们在其他语言中见到的函数,关键词是sub 开头的。子程序可以定义在任何位置,而不必要先声明。

    参数,传给perl的子程序的参数,会被放入到参数数组@_ 中,你可以通过$_[0]这种来进行访问。

    子程序可以通过检查@_的长度,来检查是否传入的参数是否正确。

    sub max {
    	if (@_ != 2) {
    		print "WARNNING...."
    	}
    }
    

    注意注意@_$_是完全不同的,一个是数组长度,一个是在for遍历中代表当前元素的变量

    私有变量

    在没有特殊说明情况下,perl中定义的变量都是全局的,这显然不是一件好事,我们可以通过my来指定变量的作用范围。

    6.输入与输出

    钻石输入符号<> , 我们假设有如下的一个脚本my.pl

    #!/usr/bin/perl
    
    while (defined($line = <>)) {	
    	chomp($line);
    	print "It was $line that I saw
    "
    }
    

    考虑到上面这段代码,钻石操作符是从文件或者标准输入流来读取文件的内容,我们创建一个临时文件,文件的内容如下

    #/tmp/demo1
    hahah
    fdsafdsa
    fdasfdsa
    feiwqrf
    

    然后我们执行命令perl /tmp/my.pl /tmp/demo1 得到的输出内容如下

    It was hahah that I saw
    It was fdsafdsa that I saw
    It was fdasfdsa that I saw
    It was feiwqrf that I saw
    

    命令修改为perl /tmp/my.pl - 就变为了从标准输入来获取内容了

    hahaha
    It was hahaha that I saw
    mymy
    It was mymy that I saw
    ^C
    

    注意,如果在使用钻石操作符去读取多个文件时,其实是这几个文件先被合并为一个大文件了,然后从头开始被顺序的读取下去。而当前正在处理的文件,会在变量$ARGV

    #my.pl
    #!/usr/bin/perl
    
    while (defined($line = <>)) {	
    	chomp($line);
    	print "FILE: $ARGV It was $line that I saw
    "
    }
    
    ---------------------------------------------------------
    
    FILE: /tmp/demo1 It was hahah that I saw
    FILE: /tmp/demo1 It was fdsafdsa that I saw
    FILE: /tmp/demo1 It was fdasfdsa that I saw
    FILE: /tmp/demo1 It was feiwqrf that I saw
    FILE: /tmp/demo2 It was 1111 that I saw
    FILE: /tmp/demo2 It was 2222 that I saw
    FILE: /tmp/demo2 It was 3333 that I saw
    

    命令行参数列表@ARGV

    文件句柄

    my $fp;
    open($fp, "</tmp/1.txt");
    while (my $line = <$fp>) {
    	....
    }
    close($fp);
    
    改变默认的文件输出
    select SOME_FILE;
    print "123
    ";
    

    一旦切换了默认的输出文件句柄,程序就会一直往那里进行输出。因此比较好的方式是,对不同的输出,进行指定。

    select LOG;
    $|=1; #这行的意思是清除缓冲区的数据
    select STDOUT;
    print LOG "I'm a log"  # 指定输出的句柄
    

    7.哈希

    哈希就像是java语言中的map结构一样。

    访问哈希

    $hash{ $someKey }

    哈希赋值

    在访问哈希的基础上,右边添加一个值,就是已完成赋值了

    访问整个hash

    想要指代整个hash,就需要使用百分号作为前缀,hash可以被转换为列表,是一些简单的键值对列表

    #!/usr/bin/perl
    
    %demo_hash = ( 
    "a" => 1, 
    "b" => 2, 
    "c" => 3, 
    "d" => 4
    );
    
    
    @demo_array = %demo_hash; # 这里会将hash转换为键值对
    my $l = @demo_array;
    print "@demo_array
    ";
    print "size=$l
    "
    
    ------ output --------
    c 3 a 1 b 2 d 4
    size=8
    

    胖箭头

    上面的方式来书写hash显然不是很方便和直观,于是就有了使用胖箭头的方式来进行

    my %hash = (
    	"a" => "1",
    	"aa" => "2",
    	"aaa" => "3"
    )
    

    哈希函数

    keys 和values
    my @k = keys %hash; # 注意这里是要访问整个hash,不用$
    my @v = values %hash;
    
    each

    如果需要罗列键值对,则可以使用each函数

    while ( ($key, $value) = eash %hash ) {
    	print "$key => $value";
    }
    
    嵌套hash
    $some_hash{a}{b}{c} = 1
    
    exists函数

    检查hash中是否有某个键

    if (exists($hash{"a"})) {
    	# do something
    }
    
    delete函数

    从hash中删除指定key的值,如果没有key,则程序会直接结束,而不会有任何的信息输出

    %ENV

    程序运行的环境变量,会在%ENV可以获取到,print "PATH is $ENV{PATH} "

    8.模块

    使用命令来查询本地是否已经安装了某个模块,例如perldoc CGI

    使用模块

    use File::Basename
    #....
    

    导入模块与自定义函数冲突

    有可能你导入的模块与自己定义的函数有着相同的名字,这个时候就需要指定导入的列表
    例如你有定义一个函数dirname,而File::Basename里面也有这个函数。

    use File::Basename qw / basename /; # 引入basename函数
    # or
    use File::Basename qw/ /; #不引入任何函数
    

    9.文件

    文件测试符

    操作符 意义
    -r 对目前用户或组来说是具有可读的
    -w 对目前用户或组来说是具有可写的
    -x 对目前用户或组来说是可执行的
    -o 由目前用户拥有
    -e 是存在的
    -R -W -X -O 是前面4种的大写,表示对实际用户
    -z 文件存在,并没有内容(对目录来说永远为假)
    -s 文件或目录存在,且有内容
    -f 是普通文件
    -d 是普通目录
    -l 是符号链接
    -C 最后一次inode变更后到今天的天数
    -M 最后一次修改到今天的天数
    -A 最后一次访问到尽头的天数

    虚拟文件句柄

    如果我们需要判断一个文件是否是可读可写的,那么我们可能需要使用如下的代码

    if ( -r $file and -w $file ) {
    	# do something
    }
    

    但实际上这是个非常不划算的操作,因为在-r的时候,我们就其实已经拿到了文件的信息,第二次没有必要再获取一次。这个时候就可以使用perl独有的虚拟句柄来解决

    if (-r $file and -w _ ) {
    	# do something
    }
    

    虚拟文件句柄_指代的是最近一次文件查询,它可可以不写在一个表达式里

    if (-r $file) {};
    if (-w _ ) {};
    

    栈式测试

    除了使用虚拟句柄以外,perl还提供了栈式测试的方式

    if (-r -w -x -o $file) {
    	# do something
    }
    

    值得注意的是,栈式写法应该用于返回的都是boolean的测试符,而不要用于返回数字的。

    stat

    stat($file)返回的是一个数组,不同位置代表了不同的信息

    localtime

    获取当前的时间

    目录句柄

    如果想要从目录里获得文件列表,那么可以使用目录句柄。

    opendir($dir, '/tmp/');
    foreach $f (readdir $dir) {
    	print "one file in /tmp/ is $f
    ";
    }
    closedir($dir);
    

    删除,重命名,软链接

    unlink(file1,file2,file3...);
    rename "oldname", "newname";   #必须属于一个盘,其他盘的话则不行
    symlink "realFile" "linkFile"; # 软链接
    

    10.进程管理

    system函数

    启动进程最简单的方式就是通过system函数,例如system "date";
    注意,如果要使用到shell环境的变量,那么一定是要使用单引号,或者转义字符来表示
    system 'ls $HOME' or system "ls $HOME"

    exec 函数

    与system函数用法基本是一样的,但system函数是在perl空闲的时候去调用子程序,而exec是perl进程自己去执行子程序任务。exec一般会同fork一起使用,在吃不准要使用什么的情况下,system一般总是对的。

    写在exec后面的代码是不会被执行的,除非是编程接管启动中的错误

    exec "date"
    die "date couldn't run: $!
    "
    

    反引号获取输出

    有的时候我们想要获取shell的执行结果,而system和exec都是输出到perl的标准输出,那我们就可以考虑使用反引号来获取

    my $now = `date`;
    print "the time is now $now
    ";
    

    奇淫巧技

    智能匹配

    考虑如下这种场景,我们想在哈希中找出包含Fred的key,并将其key打印出来。对此我们首先会想到的方法是,通过循环来遍历,然后对key判断是否包含,判定结果为true则打印出来。

    my $flag = 0;
    foreach my $key ( keys %names ) {
    	next unless $key =~ /Fred/;
    	$flag = $key;
    	last;
    }
    

    上面写法的好处是,对于任何版本的perl都使用。在5.010版本以上,提供了智能操作符,我们可以将上面的需求写作一行。
    say "i found a key matching 'Fred'" if %names ~~ /Fred/;

    正则匹配提取

    考虑到下面2个代码

    #!/usr/bin/perl
    
    my $line = "name: john, age: 18, birthday: 2003.10, height: 188";
    printf("old message= $line
    ");
    if ( $line =~ /name: (w+), age: (d+), birthday: (.+), height: (d+)/) {
    	printf("1=%s 2=%s 3=%s 4=%s
    ", $1,$2,$3,$4);
    } else {
    	printf("nothing
    ");
    }
    
    if ( $line =~ /name: w+, age: d+, birthday: (.+), height: (d+)/) {
    	printf("1=%s 2=%s 3=%s 4=%s
    ", $1,$2,$3,$4);
    } else {
    	printf("nothing
    ");
    }
    

    第一个if条件中,所有的匹配像都被圆括号包裹了,第二个if条件,前面2个没有被包裹。我们运行一下看看结果。

    old message= name: john, age: 18, birthday: 2003.10, height: 188
    1=john 2=18 3=2003.10 4=188
    1=2003.10 2=188 3= 4=
    

    我们发现第二个的if可以匹配到内容,但是$3 $4 的内容都是空的,只有$1 $2有内容,并且内容是有带括号的birthday和height的。所以,perl 正则匹配会将被()包裹的内容存放到$1 $2 ... 的变量中去,这点在实际编程的时候十分的有用。

  • 相关阅读:
    OK335x mksd.sh hacking
    Qt jsoncpp 对象拷贝、删除、函数调用 demo
    OK335xS 256M 512M nand flash make ubifs hacking
    Qt QScrollArea and layout in code
    JsonCpp Documentation
    Qt 4.8.5 jsoncpp lib
    Oracle数据库生成UUID
    freemarker得到数组的长度
    FreeMarker中if标签内的判断条件
    freemarker语法
  • 原文地址:https://www.cnblogs.com/westlin/p/14804060.html
Copyright © 2011-2022 走看看