「子程序」
用户自定义的函数,调用子程序也叫做呼叫(calling)子程序
函数名由字母、数字和下划线组成,但是不能以数字开头
sub subroutine{
statements;
}
#举个例子,定义一个寻找最大值的子程序
sub getMaximun{
my @array=sort {$a<=>$b} @_;
my$max=$array[-1];
return$max;
}
#调用子程序
my @a=qw/11 22 33 44 55/;
my$max=getMaximun(@a);
#子程序中的sort {$a <=> $b} @_是对数组元素从小到大排序,因此数组中最后一个元素值($array[-1])即最大值
1.子程序参数使用特殊数组(@_),因而第一个参数为($_[0]),以此类推
2.可以使用return语句返回数值
3.私有变量用操作符my定义
4.可用local给全局变量赋值,但不影响主程序中该变量的值,只在该子程序和被调用的子程序中发挥作用
5.最后一次运算的结果是子程序的返回值
「输入与输出」
「文件句柄」
简单而言,文件句柄就是Perl进程与外部的I/O联系的名称
通常采用open函数打开文件
#以只读方式打开文件file.txt
open(F,"
#以写入方式打开file.txt
open(F,">file.txt");
#以追加写入方式打开file.txt
open(F,">>file.txt");
「文件句柄的命名不要与特殊的文件句柄重名」
6个特殊的文件句柄
STDIN
STDOUT
STDERR
DATA
ARGV
ARGVOUT
die处理致命错误:die "Cannot creat logfile:$!";
$!表示可读的系统错误信息,例如"permission denied"或"file not found"之类
die结尾加上换行符"\n"则表示不显示行号和文件名:die "Not enough arguments\n";
warn发送警告信息,但不中断程序运行,die会终止程序运行
自动检测致命错误:use autodie;
say进行输出,与print相似,但打印每行内容时会自动加上换行符
标量变量中的文件句柄
my$rock_fh;
open$rock_fh,'<','rock.txt'or die"Could not open rocks.txt: $!";
#等效于
open my$rock_fh,'<','rock.txt'or die"Could not open rocks.txt: $!";
「正则表达式」
「简单模式」
若对象是$_的内容,只需要用一对斜线(/string/),配合if/while的条件表达式
「Unicode属性」
匹配某项属性
if(/\p{Space}/){
print"The string has some whitespace.\n";
}
#若是匹配数字,可使用\p{Digit}
if(/\p{Digit}/){
print"The string has some digital number.\n";
}
#若想匹配不包含特定属性的字符串,则使用\P
if(/\P{Digit}/){
print"The string has no digital number.\n";
}
「元字符」
点号(.)只能任意匹配一个字符(换行符除外)
匹配句号需要加反斜线(\)
反斜线使元字符失去特殊作用
(^)匹配行首,字符集里表示求补集
($)匹配行尾
(.)除新行外的任一字符,在s/中匹配包括换行符在内的任一字符
(|)匹配左边或右边,择一匹配
'()'模式分组字符,反向引用括号中匹配的文字,即捕获组
反向引用写法(\1、\2,数字表示对应顺序的捕获组)
消除连续数字产生的歧义
\g{N},其中N表示组号,若N为负数,则表示从\g{N}位置向前数第N个括号
「如何理解模式分组和反向引用?」
通过元字符我们知道如何去匹配单个字符,但若要匹配字符串,特别字符串中有2处及以上未知子串时,就需要通过分组捕获,再通过反向引用访问捕获到的字符串
例如,我爬虫获取了梦华录电视剧剧集和对应的人物信息,想要整理出每一集中出现的人物
"Menghualu01_Zhaopaner_Guqianfan"=~ /Menghualu([0-9]*)_([a-zA-Z]*)_([a-zA-Z]*)/;
print"梦华录第$1集人物:$2$3\n";
#运行结果:
梦华录第01集人物:Zhaopaner Guqianfan
#这里使用圆括号对匹配的子串作分组,从左到右分别是1、2和3
#因为Perl中会将匹配的内容存入特殊变量$N中,我们可以通过$1、$2和$3访问捕获到的剧集和人物信息
#其中,$1表示剧集数,$2和$3表示对应剧集中出现的人物名字
「量词」
星号(*)匹配零次或多次
加号(+)匹配一次或多次
问号(?)匹配零次或一次
{n}匹配n次
{n,}至少匹配n次
{n,m}匹配n-m次,如a{1-10}表示匹配重复1到100次的字母a
「字符集」
'[]'表示一类字符集中的任意一个,匹配单个字符;'-'表示范围
如[0-9]表示匹配数字0-9,[^0-9]表示匹配除0-9数字外的字符
字符集简写:
\d => [0-9],\D => [^0-9]
\w => [a-zA-Z0-9_],\W => [^a-zA-Z0-9_]
\s => [\f\t\n\r],\S => [^\f\t\n\r]
\h => [\t]
\v => [\f\n\r]
\R =>任意类型的换行符
「正则匹配」
/i:表示不区分大小写,/chr/i
/s:点号(.)在其中表示匹配任意字符,包括换行符
/x:忽略空白符,更易阅读
$a="hello\ntomorrow is another world";
if($a=~ /hello.*world/s){
print"it's ok.\n";
}
学完一轮基础的Perl,下面简单分析一个根据id信息提取相应序列的perl脚本(https://blog.csdn.net/weixin_40099163/article/details/88723572)
学习编程最快的方式就是看懂别人写的代码
#!/usr/bin/perl -w
1 unless(@ARGV==3){
2 die"Usage: perl$0 error:$!\n";
3 }
4 my($lst,$input,$output)=@ARGV;
5 open LST,$lst;
6 open INPUT,$input;
7 open OUTPUT,">$output";
8while(){
9 chomp;
10if($_=~ /^>..*/){
11$keys=$_;
12 }
13else{
14$hash{$keys} .=$_;
15 }
16 }
17while(){
18 chomp;
19if($_=~ /^>..*/){
20$ID=$_;
21printOUTPUT$ID."\n".$hash{$ID}."\n";
22 }
23else{
24$ID=">".$_;
25printOUTPUT$ID."\n".$hash{$ID}."\n";
26 }
27 }
第1-3行,@ARGV是收集命令行参数的数组,这里规定用户必须提供3个参数,即ID列表文件(ID_lst)、输入序列文件(input_fasta)和输出序列文件(output),其中第2行的表示该脚本的名称
第4行,将用户输入的3个文件名依次赋值给数组@ARGV
第5行,通过文件句柄LST打开ID列表文件
第6行,通过文件句柄INPUT打开输入序列文件
第7行,通过文件句柄OUTPUT以写入方式打开输出序列文件
第8行,遍历输入序列文件
第9行,去除行尾换行符
第10行,判断该行是否以大于号(>)开头,即判断该行是否为序列ID
第11行,将匹配成功行的内容赋值给keys,keys即序列ID
第14行,将匹配失败行的内容赋值给哈希%hash{keys},即将ID存为哈希的键,ID对应的序列存为哈希键对应的值,其中出现的双目赋值符(.=)考虑了序列为多行格式的情况
第17行,遍历输入的ID列表文件
第18行,同第9行
第19行,判断用户输入的ID名是否带大于号
第20行,把匹配成功的行赋值给$ID
第21行,通过哈希中键值对一一对应的关系,打印输出序列文件 第24行,若ID不以大于号开头,则在开头加上大于号再输出到OUTPUT