perl one-liners explained 中文版 (二)行计数

perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book/

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

行计数

9.给文件打印行号。

和一个行代码中说明一样,“-p”作用在让Perl在命令行开启循环执行代码(通过”-e”指出),循环的读出输入的每一行存储在“$”变量中,执行代码,接着打印出“$”内容。

本例中我们仅仅通过修改“$_”在其前附加“$.”的内容。特定变量“$.”保存当前输入行的行号。

结果就是每一行标上了行号。

10.仅给非空行打印行号

这行代码我们是使用了“行为if条件”语句,当条件为真的时候,执行行为。本例中条件是一个正则表达式“/./”,用来匹配除换行符外任何一个字符(就是匹配非空行);行为是“$=++$a.”“$”,由变量“$a”值在每行增加1,并附加到当前行前面。由于没有设置strict 编译,$a无需事先定义。

本语句执行结果是每一个非空行$a值1并附加到行前面。对每个空行没有任操作,只输出空行。

11.打印文件非空行及其行号(删掉空行)

和上例相比,本例用“-n”代替了上“-p”两者都执行行循环,唯一区别是“-p”自动会打印“_$”的内容,而-n不打印,所以需要用print显式打印出需要打印的内容。

由于正则不会匹配空行,所以对空行不会执行打印动作,所以就会跳过空行。

12.给所有行标行号,但是只打印非空行的行号

这行代码和例10相似。我们只调整“$_”变量仅仅在匹配正则(至少一个非换行字符,非空行)时附加行号($.)。所有其他行打印时候,没有处理,无行号。

13.给匹配模式行标行号,其他未匹配的仅打印。

本行代码也是用了“行为if条件”语句,但是条件是一个模式(正则表达式)“/regex/”。行为表现和例10一样。这儿不再赘述。

14.仅给匹配的行标行号和打印。

本例和例11基本上一样,唯一不同是打印匹配模式“regex/”的行。

15.给所有行标行号,但是打印匹配模式行的行号。

本例和上一列以及例12类似。在这儿当匹配漠视的时候附加行号到当前行,否则,仅打印而无附加行号。

16.给文件标格式化的行号(模仿 cat -n)

这个行代码使用带格式化的“printf”打印函数,打印行号。在本例中为左对齐5字符长度。 其他比较好的格式是“%5d” ,表示右对其5个字符长度。“%05d”表示右对齐5字符长度,用0填充长度(5用00005表示)。

17.打印文件行的数量(模仿 wc -l)

这行代码使用“END”语句块,这个语句块表现和awk中的基本一样,在整个程序执行最后时候执行。本例中用“-n”参数隐藏了输入的循环过程。在所有输入循环结束后,特殊变量“$.”保存了输入过的行号。“END”语句块打印出了这个变量。“-l”参数设置输出记录分割符为换行符(这样我们就不必去打印“$.\n”)。

另一种实现方式是:

这是比较费解的一个,如果你知道Perl 上下文的就好理解多了。本行代码中“()=<>”部分是个在列表上下文中的<>操作符,<>操作符会读整个文件所有行。同时,在标量上下文中,“$n”取得数量。这样“$n=()=<>”结构就等与输入的行数,也就是文件的行数。print语句打印出这个数。“-l”参数使得输出数量后输出一个换行符。

下面这行代码表现也一样,除了长度不同外:

完全显式的版本是:

另一种方式是:

这行代码使用了eskimo操作符“}{”和“-n”命令行参数。在例11中解释过“-n”参数强制Perl执行一个“while(<>){}”循环。 eskimo操作符强制Perl跳过这个循环,程序的实际执行是:

这很明显就是执行所有输入循环后,打印出“$.”,这就是行号。

18.打印一个文件中的非空行数

这行代码使用“grep”函数,他的和Unix命令行同名工具功能相近。对给予的列表值,“grep {condition}”返回匹配条件的值。本例中条件是一个匹配至少一个字符的正则表达式,所以输入行被筛选了,“grep{/./}”返回所有的非空行。为了得到列表的数量,我们使用scalar函数,强制其为标量上下文中,这样就得到列表数量。最后打印出其结果。

一个更精妙版本的行代码还可以用“~~”代替scalar(),这能更短一点:

这还可以更短:

19.打印文件中空行的数量

本行代码中使用变量$a计算多少次空行,结束循环后,在END块打印$a值。最后输出时使用了“$a+0”结构,确保文件中没有空行是打印出0。

我们也可以修改上一例的代码:

“~~”代替后的版本:

最后两个版本不是怎么高效,因为他们需要把整个文件读到内存再筛选。而第一个是逐行处理的。

20.打印文件中匹配模式的行数(模仿 grep -c)

这个行代码基本上和前一个一样,只不过用了更一般的正则表达式/regex/