zoukankan      html  css  js  c++  java
  • Perl学习笔记05——输入与输出

    读取标准输入

    之所以称<STDIN>行输入操作符,是因为它真的是每次读取一行,用一对尖括号表示。被它包围的文件句柄表示数据来源

    由于行输入操作符在读到文件结尾,没有可读内容的时候会返回undef,所以借此可以跳出循环。

    while(defined($line = <STDIN>)){
        print "I saw $line";    
    }

    由于这样的额操作很常见,Perl提供了简写形式:

    while(<STDIN>){
        print "I saw $_";
    }

     完整展开的等效写法:

    while (defined($_ = <STDIN>)){
        print "I saw $_";
    }

    注意:

    1.这个简写行为只有在上面这种写法中才适用。如果把行输入操作符放在其他任何地方,特别是单独成行时,它不会读取一行输入并存到$_

    唯独while循环的条件表达式中只有行输入操作符时,才会按照这个方式运行。换句话说,若条件表达式中写了其他代码,此行为将失效。

    2.行输入操作符(<STDIN>)和Perl的默认变量$_之间并无直接关联,只是在这个简写里,输入的内容恰好存到默认变量中而已。

    比较这两个循环的差别:

    while(<STDIN>){
        print "I saw $_";
    }

    foreach(<STDIN>){
        print "I saw $_";
    }

    区别:

    while循环里,Perl每次读取一行输入,把它存到某个变量并执行循环体,而后再尝试获取后续输入。

    但在foreach循环里,行输入操作符会按列表上下文处理,所以要做的第一件事就是把所有的输入都读进来,按列表返回。数据量小的话没关系,如果输入来自一个400M的文件,就要准备相应大小的内存来安顿!所以没啥特殊情况,尽量还是使用while循环,一次处理一行。

    来自钻石操作符的输入

    另一种读取输入的方法:钻石操作符<>

    一般来说,“键盘”就是标准输入,“屏幕”就是标准输出。

    钻石操作符<>,能让程序在处理调用参数时,提供类似于标准Unix工具程序的功能。

    如果想用Perl编写类似catsedawksortgreplpr之类的工具程序,一边从标准输入拿数据,一边输出结果到标准输出,钻石操作符将会是你的好帮手。

    但如果要支持复杂的参数,单单靠钻石操作符也是不行的。

    $ ./my_program fred barney betty

    这条命令的含义:

    执行当前目录的my_program程序,让它依次处理文件fredbarneybetty(当然,这样写的话,文件也要在程序执行的目录下)

     

    若不提供任何参数,程序会从标准输入流采集数据(也就是“键盘”)。

    如果参数是连字符(-),则表示从标准输入(也就是“键盘”)读取数据。

    所以,假如调用参数是fred - betty,那么程序应该先处理文件fred,然后处理标准输入流中提供的数据,最后才是文件betty

    钻石操作符是行输入操作符的特例,不过它并不是从键盘取得输入,而是从用户指定的位置读取。

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

     钻石操作符只有在碰到所有输入的结尾时才会返回undef(然后程序就跳出while循环了)。

    当前正在处理的文件名会被保存在特殊变量$ARGV中。如果当前是从标准输入获得数据,那么当前文件名就会是连字符-”。

    由于钻石操作符是行输入操作符的一种特例,因此可以只用之前的简写,将输入读取到默认变量$_里:

    while (<>){
        chomp;  #不加参数时,chomp会直接作用在$_上
        print "It was $_ that I saw!
    ";
    }

    双钻石操作符

    5.22版本的时候,Perl修复了钻石操作符的一个问题:如果命令行上传入的文件名带有特殊字符,比如|,就会引发管道操作Perl会打开管道,从外部程序的输出结果读取输入内容。所以这个过程启动另外一个外部程序,而非打开某个名字的文件

    use v5.22;
    
    while (<<>>){
        chomp;  
        print "It was $_ that I saw!
    ";
    }

    如果是Perl 5.22及以后的版本,最好默认使用双钻石操作符。

    调用参数

    从技术上讲,钻石操作符并不会检查命令行参数,它看到的不过是放在@ARGV数组里面的数据。

    @ARGV是由Perl解释器事先建立的特殊数组,并在程序运行前根据命令行参数初始化。所以本质上它的使用方式和其它数组没有什么不同(除了用了奇怪的全大写名称之外),只不过在程序开始运行时@ARGV里就已经塞满了调用参数。

    既然@ARGV和其他数组一样,就可以用shift移出@ARGV中的元素,或者用foreach逐个处理,也可以检查是否有参数是以连字符(-)开头的,然后将它们当成调用选项处理(就像Perl对待自己的-w选项一样)。

    钻石操作符会查看数组@ARGV,然后决定该用哪些文件名,如果它找到的是空列表(也就是执行时没有给参数),就会改用标准输入流,否则,就会使用@ARGV里的文件列表。

    NOTE

    程序运行之后,只要尚未使用钻石操作符,就可以对@ARGV动点手脚,可以这样处理三个特定的文件,不管用户在命令行参数中制定了什么:

    @ARGV = qw# larry moe curly #;   #强制让钻石操作符只读取这三个文件
    while(<>){
        chomp;
        print "It was $_ that I saw.
    ";
    }

    输出到标准输出

    ▲直接使用数组和使用数组内插在打印效果上是不同的:

    print @array;  #元素间没有空格分隔
    
    print "@array";  #元素间有空格分隔

    注意:

    在使用数组内插的写法时,如果每个元素都是以换行符结尾,会输入如下结果:

    fred
     barney
     betty

    因为Perl把数组内插到字符串中时,会在每个元素之间加上空格(实际上是特殊变量$定义的内容,默认是空格字符)。

    print处理的是待打印的字符串列表,因此它的参数会在列表上下文中被执行。

    而钻石操作符(行输入操作符的特殊形式)在列表上下文中会返回由许多输入行组成的列表,所以她们可以配合工作。

    print <>;  #相当于Unix下的/bin/cat命令
    print sort <>;  #相当于Unix下的/bin/sort命令

    print后面的括号其实可有可无。原则:除非会改变表达式意义,否则括号可以省略。

    print("Hello,world!
    ");
    print "Hello,world!
    ";

    假如print调用看起来像函数调用,那它就是一个函数调用。

    调用函数时,函数名后面必须紧接着一对括号,包含调用函数的参数。

    print (2+3);

    它会输出5,然后和其他函数一样返回某个值。print的返回值不是真就是假,代表print是否执行成功,通常就是返回1

    $result = print("hello, world!
    ");  #返回1

    注意:

    print (2+3)*4  #糟糕!会打印5

    它会打印5,然后Perl会取得print的返回值1,再将这个值乘以4,然后又将这项乘积丢失。

    没有括号的时候,print是列表操作符,会把其后的列表里的所有东西全都输出来。

    假如print后面紧跟着左括号,它就是一个函数调用,只会将括号内的东西输出来。

    因为上面的代码有括号,所以就相当于这样写:

    (print(2+3))*4;  #糟糕!

    如果使用了-w 或者加上use warningsPerl就会给出提醒。

    修复的办法:

    print ((2+3)*4);

    printf格式化输出

    printf是控制能力比print更强的操作符。

    printf操作符的参数包括“格式字符串”及“要输出的数据列表”。格式字符串就是用来填空的模板,代表你想要的输出格式。

    printf "Hello, %s; your password expires in %d days!
    ",$usr, $days_to_die;

    格式字符串里可以有多个转换,每种转换都会以百分符号(%)开头,然后以某个字母结尾(在这两个符号之间可以存在另外的格式定义)。

    后面的列表里元素的个数应该和转换的数目一样多,如果数目不一样,就无法正确运行。

    printf常用转换格式:(可以查看perlfunc文档的<sprintf>部分)

    1%g

    要以恰当的形式输出某个数字,可以使用%g,它会按需要自动输出浮点数、整数甚至是指数形式。

    printf "%g %g %g
    ", 5/2,51/17,51**17; #2.5 3 1.0683e+029

    2%d%x%o

    %d表示十进制整数,它会舍去小数点后的数字。注意,它会无条件截断,而非四舍五入。

    printf "in %d days!
    ", 17.85;  #输出:in 17 days!

     %x表示十六进制数,%o表示八进制数。

    printf "in %x days!
    ",17;  #输出:in 11 days!
    printf "in %o days!
    ",17;  #输出:in 21 days!

     3)指定宽度,如果数据太长,字段会按需要自动扩展。

    printf "%6d
    ", 42;  #输出:````42(`代表一个空格)
    printf "%3d
    ", 2001.95;  #输出:2001

     4%s

    %s代表字符串格式,它的功能其实就是字符串内插,但同时还支持设定字符宽度。

    printf "%10s
    ", "wilma";  #输出:`````wilma

    如果宽度字段是负数,则表示左对齐(适用于上述各种转换格式):

    printf "%-15s
    ", 'flintstone';  #输出:flintstone`````

    5%f

    %f表示浮点数转换格式,它可以按需四舍五入,甚至可以指定小数点后的位数:

    printf "%12f
    ",6*7+2/3;  #输出:```42.666667
    printf "%12.3f
    ",6*7+2/3;  #输出:``````42.667
    printf "%12.0f
    ",6*7+2/3;  #输出:``````````43
  • 相关阅读:
    职场“潜”规则:心法和技法
    JVM参数配置
    python-编码
    pyserial库-串口通讯模块
    Arduino-舵机
    Arduino-中断
    Arduino-一些函数
    Arduino-位操作
    Nginx (一)Windows下编译Nginx源码以及安装 nginx for windows方法步骤
    MSYS2环境搭建
  • 原文地址:https://www.cnblogs.com/yd-yfb/p/14076851.html
Copyright © 2011-2022 走看看