perl语言——正则表达式
一、正则表达式
在perl里面正则表达式(regular expression)又叫模式(pattern),用来匹配或者不匹配某个字符串的特征模板
二、几个正则中常用的符号
在介绍正则表达式的内容之前,先介绍几个符号。
- 元字符 . \ ()
perl里面的某些字符具有特殊含义,叫做元字符。比如:
点号. : 表示任意一个字符,不包括换行符
反斜杠 \ : 表示字符本身,忽略它的特殊含义。比如.就表示点号本身,而不是任意一个字符。
圆括号 () : 将模式分成一个个捕获组。
量词 + * ?
“+” :表示匹配前面的条目一次或一次以上。
1
2
3abc+ : 匹配字符c一次或者一次以上,可以匹配abc,abcc,abccc
ab[0-9]+ :匹配任意0到9的数字一次或一次以上,如 abc0 ,abc11,,
ab(cd)+ : 匹配组(cd)一次或一次以上,如abcd,abcdcd,abcdcdcd,,“*” : 表示匹配前面条目0次或任意次
“?” : 表示匹配前面条目0次或1次
模式分组 ()
将模式分成多个捕获组,比如 “ ([a-z]+)([0-9]+.abc) “,将模式单独分出两个组。
在《perl语言入门》书中还讲到,可以利用刚刚从圆括号中匹配到的字符再次匹配。比如
1
2
3
4
5
6
7
8
9
10
11$_ = "abba" ## 正则表达式默认对变量 $_ 进行匹配
if( m/(.)\1/ ) { # m// 是模式的界定符,下面讲
# 这里会匹配 bb,\1 的意思是再次匹配第一个捕获组的内容,匹配了两次b
print "ok\n";
}
## 如果存在多个圆括号,如何区分哪个括号是第几组?依次计算左括号的序号就可以
$_ = "yabba dabba doo"
if (m/y((.)(.)\3\2) d\1/){ # yabba dabba
print "ok\n";
}
也可以将\1 \2写成 \g{1} \g{2},含义一样,又不容易误解
4. **则一匹配 | **
要么匹配左边要么匹配右边
5. **字符集 [] **
存在[]中的一个字符
1
2[a-z] : 任意a到z的一个字符
[a-z0-9] ,[a-zA-Z],都可以
字符集简写
- \d : 表示一个数字
- \s : 表示一个空格
- 脱字符 ^
脱字符用在字符集符号[]中,表示不包含这些内容。1
2
3
4
5[^a-z] :不包含a到z
[^\d] : 不包含数字 , 等价于 [\D]
[^\s] : 不包含空格 等价于[\S]
[\d\D] : 匹配任意字符,包括换行符
[^\d\D] : 不匹配任何字符
三、用正则表达式进行匹配
1. 模式定界符 m//
前面程序中经常出现 m / 模式 /
,其中// 就是模式的定界符,斜杠可以用其他符号,比如,#等 m## ,m*
2. 模式匹配修饰符
模式匹配修饰符(modifier)又叫标志(flag),用在模式定界符后面,用来改变默认的匹配行为的。
- /i :大小写无关的匹配,这里的/i,/是m//中的/,如果是m##,那么就是#i
1
2$_ = "ABC";
m/abc/i ; # 也能匹配成功 - /s : 匹配任意字符
原来点号. 不能匹配换行符,现在也可以了
3. /x :可以随便加入空白符
为了便于阅读,可以在模式中随便加空白符。但是这样的原先模式中存在的空白符就没用了,得换成\s形式
4. 还可以选择字符的解释方式 /a /u /l
但我不是很明白什么意思
这几种模式修饰符可以同时使用
3. 锚位
- 开头结尾定位^ $ \A \Z
perl5中
\A匹配字符串的绝对开头,这个字符串中间可能有换行符。\z(小写)匹配字符串的绝对末尾,\Z(大写)也是匹配字符串绝对末尾,但是可以允许后面有换行符。
^也是匹配字符串的开头,$匹配字符串的末尾。后面会讲可以用$和/m对多行内容进行匹配,这时^匹配一行开头,$匹配一行结尾。
- 单词定位 \b \b
1
2
3$_ = "abc";
m/ \babc\b /x; # 匹配单词abc,
m/ \bab\b /x; # 匹配失败,没有ab的单词,只有abc
4. 匹配成功会返回1
可以作为if语句的判断条件,比如下一小节中的例子。
5. 绑定操作符 =~
前面的模式匹配都是自动匹配到默认变量$_上,现在可以指定要匹配的变量。
1
2
3$str = "abc";
if($str =~ m/ \babc\b /x) # 匹配$str变量中的abc
{print "ok\n";}
6. 模式中内插
可以将模式内容先 保存在某个变量里,然后用在模式定界符内
1
2
3
4
5
6$str = "abc";
$pattern = "\babc\b";
if($str =~ m/$pattern/x)
{
print "ok\n";
}
7. 捕获变量
捕获变量是用来保存捕获组中捕获到的内容。
- 默认的捕获变量
默认的捕获变量是$1,$2,这些,用来保存捕获组1,捕获组2,,中的内容,捕获组是第几个组是看左括号是第几个。
1
2
3
4
5
6$str = "hello world";
if($str =~ m/ (\bhello\b)\s(\bworld\b) /x){
print $1," ",$2;
# 第一个捕获组得到的内容存在$1,第二个存在$2,
# 打印输出 hello world
}
- 捕获变量的生存期
这些捕获变量能够保存到下次捕获成功,也就是说如果匹配失败,不会改变上次匹配成功捕获的内容。
3. 不捕获模式
如果不想捕获某个捕获组中的内容,在这个组的左括号后加?:
1
2
3
4
5
6
7$str = "hello world";
if($str =~ m/ (?:\bhello\b)\s(\bworld\b) /x){
print $1," ",$2;
# 第一个捕获组不捕获,第二个捕获到world存在变量$1,
# 打印输出 “world ”
# 变量$2没有内容
}
4. 自己指定(命名)捕获变量 %+
perl5.10中增加了对捕获内容直接命名的方法,将捕获的内容存在一个哈希表中 %+,表中的键是认为设定的捕获变量,键对应的值是变量内容。
比如这样一个捕获组——(?
8. 通用量词
1 |
|
9. 保存匹配的结果
在对文件中的行循环匹配的时候,有的时候能匹配到,有的时候匹配不到,如果匹配到就会更新捕获变量,$1,$2或者自己定义的哈希对(这些变量都是只读的)。但如果没匹配到,那么这些变量不会改变,但我们不知道他到底有没有匹配到,可能匹配到了,但他的值跟上一次匹配的一样,那么这些变量还是没变,那怎么办呢?
所以在每次匹配的时候将匹配到的值保存出来,下一次匹配之前再清空他。
1 |
|
四、正则表达式处理文本
1. 用 s/// 进行替换
查找并替换
1 |
|
/g进行全局替换,全部都替换
1 |
|
而
1 |
|
** 也可以 s###,等其他的定界符**
大小写转换
\U全部大写 \L全部小写
1 |
|
2. split操作符
split操作符,根据字符将字符串分成多组,返回一个数组保存结果
1 |
|
split默认以空白符切分变量$_
1
2
3$_str_ = "hello world";
@res = split; # 以空格为界切分$_,数组@res保存结果
print $res[0],"\n"; # hello
3. join函数
与split相反的作用,将多个字符串连接起来
1
2
3
4
5 $str = "hello world";
@res = split " ",$str;
print $res[0],"\n";
$str = join "+",@res;
print "$str\n"; # hello+world
** join函数连接的列表至少要有两个元素**
4. 列表上下文中的m//
如果m//使用的上下文是列表环境,那么m//将匹配到的所有内容返回成列表
1
2
3
4
5 $str = "A good day";
my ($first,$second,$third) = $str =~ m/ (\S+)\s(\S+)\s(\S+) /x;
print "$first+$second+$third\n";
## 输出 A+good+day
## 将各个捕获组的内容保存到列表中的变量里
**5. 跨行的模式匹配 /m **
假如有一个文件program.log内容如下.
1 |
|
读取文件内容并修改:
1 |
|
输出:
1 |
|
com.log文件的内容:
1 |
|
如果不加\m,那么com.log中的内容为:
1 |
|
6. 一次更新多个文件 $^I变量**
对于一个文件command.log内容如下:
1 |
|
我们想将author改成dong yk,日期设为当前日期,去掉phone那行。
脚本如下:
1 |
|
钻石操作符<>会读取命令行参数指定的文件的内容。**$^I变量和<>同时使用,**在<>打开文件的时候会将原来文件复制一份,这个文件以$^I变量内容为后缀。
必须要设置$^I变量,要不然print输出到控制台,因为<>读取的内容默认存在$_中,print默认输出$_的值
7. 从命令行直接编辑
假如有一个文件program.log内容如下.
1 |
|
1 |
|
program.log文件内容变成:
1 |
|
-p : 让perl生成一段小程序
-i :功能类似$^I变量,以自定义的后缀保存源文件,这里的是.bak后缀
-w:开启警告
-e :告诉perl后面跟着可执行程序
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!