[关闭]
@guoxs 2015-09-12T14:23:20.000000Z 字数 4632 阅读 4015

正则表达式入门

正则表达式


正则表达式 = 元字符 + 文字

1、常用的元字符

"*" :通配符,任意文本
"?" :任意单个字符
"^":匹配一行的开始
"$"匹配一行的结束
"[ea]":字符组,匹配e或a。例如:H[123456]匹配<H1><H2><H3><H4><H5><H6>
"-":字符组元字符,表示一个范围。如上例还可表示为<H[1-6>
"|":或,匹配任意字表达式,同样的在字符组里字是一个普通的字符
"\<"、">":元字符序列,单词分界符。

,.

一个字符组只能匹配目标文本中的单个字符,而每个多选结构自身都可能是完整的正则表达式,都可以匹配任意长度的文本。

例子:

  1. "^cat$":只包含cat的行,无多余单词,无空的字符
  2. "^$":匹配一个空行
  3. "^":匹配行开头,无意义
  4. "From|Subject|Date: ""^(From|Subject|Date): "的区别
  5. "\<cat\>":匹配单词开头,然后是cat,然后是单词结尾

2、排除型字符组

  1. "^1-6":匹配除16外的任何字符
  2. ".":匹配任意字符的字符组

注意:对于"Iraq",用"q[^u]"是无法匹配的,因为q后无字符,而一个字符组,即使是\排除型字符组,也需要匹配一个字符。

3、可选项元素

  1. "?":代表可选项,匹配一个或0个。
  2. "+":之后紧邻的元素出现一次或多次
  3. "*":之前紧邻的元素出现任意多次,或者不出现
  4. "...*":匹配尽可能多的次数,如果实在无法匹配,也不要紧
  5. "...+":匹配尽可能多的次数,但如果一次都无法匹配,则报错
  6. "...{min,max}":区间量词

反向引用:匹配与表达式先前部分同样的文本
例如:

  1. "([a-z])([0-9])\1\2""\1"代表"[a-z]"匹配的内容,而"\2"代表"[0-9]"匹配的内容。

4、转义

"/":转义符

  1. " "[^"]*" ":匹配引号内的字符串,用来匹配字符串的开头和结尾的引号,用" [^"] "来匹配除双引号外的任意字符,用" * "来表示两引号间可以存在任意数目的非双引号字符。

匹配美元:

  1. "^[+-]?[0-9]+(\.[0-9]*)?$":不能匹配像".369"这样的小数

分组与捕获:

  1. "^([-+]?[0-9]+(\.[0-9]*)?)(CF)$":其中有三个括号,会有三个捕获项。分别保存于$1$2$3中。
  2. "(?:)":只分组不捕获。例如"^([-+]?[0-9]+(?:\.[0-9]*)?)(CF)$"只有两个捕获组,"(?:\.[0-9]*)"不在捕获组之内。

$(?:)表示非捕获组,使用非捕获组效率更高,因为引擎不需要记忆捕获文本。

5、perl语言中的正则表达式

常见字符:

  1. "\t":制表符
  2. "\n":换行符
  3. "\r":回车符
  4. "\b":匹配字符串开头或结尾,单词分界符
  5. "\s":匹配任意空白字符,空白包括(空格符、制表符、换行符、回车符、进纸符)
  6. "\S":匹配除"\s"外的任意字符
  7. "\w":等同于"[a-zA-z0-9]""\w+"匹配一个单词
  8. "\W":匹配除"\w"外的任意字符
  9. "\d":[0-9],匹配数字
  10. "\D""[^0-9]"

例子:

  1. "m/^([-+]?[0-9]+(\.[0-9]*)?)\s*([CF])$/i"i放在m/.../结构后面,不是正则表达式的一部分,而是m/.../的一部分,告诉Perl进行不区分大小写的匹配。

Perl用$variable =~ m/regex/来判断一个正则表达式是否匹配某个字符串,m表示“匹配”,斜线标注正则表达式边界,整个表达式返回一个布尔值。

使用正则表达式来修改文本
通式:$var =~ s/regex/replacement/
例子:
$var =~ s/\bJeff\b/Jeff/i:"jeff"这个单词无论大小写都会被替换成"Jeff"。

问:选择12.345这样的浮点数,第三位小数不是0则保留。
$num =~ s/(\.\d\d[1-9]?)\d*/$1/:前两个"\d\d"表示匹配小数点后两位小数,"d[1-9]?"匹配第三个小数,"(.\d\d[1-9]?)"中捕获的内容保存在$1中,然后去替换原数字。

  1. " .* "表示一组任意字符。

6、环视

环视功能:不匹配任何字符,只匹配文本中的特定位置。

例子:将 Jeffs修改为Jeff's。

s/(?<=\bJeff)(?=s\b)/'/g:匹配一个位置,该位置在"Jeff"后,在"s"前,在该位置插入'

  1. "(?<!\w)(?=\w)|(?<=\w)(?!\w)"等价于"\b",

问:修改数字为"12,345,678"这样的形式。

  1. s/(?<=\d)(?=\d\d\d)+(?!\b)/,/g

不使用逆序环视添加逗号

  1. s/(\d)((\d\d\d)+\d)/$1,$2/g,存在问题,((\d\d\d)+\b)为最终匹配文本,不能作为未匹配文本使用g,会匹配到"12,34567"这样的数字
  2. 解决方法:
  3. while($text =~ s/(\d)((\d\d\d)+b\)/$1,$2/g)
  4. {
  5. 循环不需任何操作
  6. }

大多数OS系统采用换行符作为一行的终结,而某些操作系统(主要为Windows)采用“回车+换行”结合体表示。

7、强制行锚点匹配模式

^ $匹配的不是逻辑行的开头与结尾,而是整个字符的串的开头和结尾的位置,但在强制行锚点匹配模式下,^ $会从字符串模式切换到逻辑行模式。在Perl中,使用/m选择此模式。

例如:

  1. $text=~ s/^$/<p>/mg:全局将空行替换为<p>标签。
  2. 若一行中有空白符则需用"^ *$"或者"^[ \t\r]*$",或者用"$text =~ s/^/s*$/<p>/mg"更为安全。

将E-mail转换为超链接形式

  1. 例如:ifriedl@oreilly.com 转化为 <a href="mailto:ifriedl@oreilly.com">ifriedl@oreilly.com</a>。
  2. => $text =~ s/\b(username regex\@hostname regex)\b/<a href="mailto:$1">$1<\/a>/g;两个反斜杠是转义。添加单词分分界符"\b...\b"是为了避免不完整匹配的情况。

匹配主机与用户名

用户名第一个一般是字母,之后没有太多限制,故可以\w[-.\w]*匹配,对于主机名,两个点号之间必须要有分隔符,并且结尾一般为特定几中格式,故使用\w+(\.\w+)*\.(com|edu|info)(实际结尾还有其他格式)。
但是,使用\w还是有问题的,因为有些系统会匹配一些非ASCII字母,这里可以用[a-zA-Z0-9],主机名可能包含连字符,故完整版:[-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info)

如果表达式较长,可以使用\x修饰符。\x允许用户以“宽松排列”编排表达式,也容许出现#开头的注释。\x只能用于正则表达式本身,而不能用于replacement字符串。

  1. undef s/; #进入“文件读取”模式
  2. $text = <>; #读入命令行中指定的第一个文件名
  3. $text =~ s/&/&amp;/g; #把基本的HTML...
  4. $text =~ s/</&lt;/g; ...字符&、<和>...
  5. $text =~ s/>/&gt;/g; ...进行HTML转义
  6. $text =~ s/^\s*$/<p>/mg; #划分段落
  7. #转化为连接形式...
  8. $text =~ s{
  9. \b
  10. #把地址保存到$1...
  11. (
  12. \w[-.\w]* #username
  13. \@
  14. [-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) #hostname
  15. )
  16. \b
  17. }{<a href="mailto:$1">$1</a>}gix
  18. print $text; #最后,显示HTML文本

将HTTP URL转化为连接形式
HTTP URL的基本形式是是http://hostname/path,其中path部分可选。
有几点需要注意:

  1. 1 URLpath部分可以是各种字符,使用"[-a-z0-9_:@&?=+,.!/~*`%$]*",在使用Perl时,必须对 @ $进行转义。
  2. 2 path后面不能接"\b",因为URL之后通常会接标点符号,如果末尾有"\b",就不能匹配。
  3. 3、末尾的标点不能成为链接的一部分,故可使用否定逆序环视"(?<![.,?!])"即可。

完整程序:

  1. undef s/; #进入“文件读取”模式
  2. $text = <>; #读入命令行中指定的第一个文件名
  3. $text =~ s/&/&amp;/g; #把基本的HTML...
  4. $text =~ s/</&lt;/g; ...字符&、<和>...
  5. $text =~ s/>/&gt;/g; ...进行HTML转义
  6. $text =~ s/^\s*$/<p>/mg; #划分段落
  7. #转化为连接形式...
  8. $text =~ s{
  9. \b
  10. #把地址保存到$1...
  11. (
  12. \w[-.\w]* #username
  13. \@
  14. [-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) #hostname
  15. )
  16. \b
  17. }{<a href="mailto:$1">$1</a>}gix
  18. #将HTTP URL转化为链接形式...
  19. $text =~ s{
  20. \b
  21. #将URL 保存至$1...
  22. (
  23. http:// [-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) \b #hostname
  24. / [-a-z0-9_:\@&?=+,.!/~*`%\$]* #path不一定会出现
  25. (?<![.,?!]) #不能以[.,?!]结尾
  26. )?
  27. }{{<a href="$1">$1</a>}gix;
  28. print $text; #最后,显示HTML文本

8、构建正则表达式库

使用Perl的qr操作符,接收一个正则表达式,生成一个"regex对象",作为变量保存,方便以后调用。

  1. $HostnameRegex = qr/[-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info)/i;

问:为什么有时候@ $需要转义?
$即可表示单词结尾又可以标识变量,但在字符组内部,不能用来表示单次结尾,只能通过转义后标识变量。
@在Perl中表示数组,使用字符时需要转义。

在Perl中,正则表达式是“基础级别的”,也就是说,基本的运算符可以直接作用于正则表达式,就像+、-作用于数字一样,这样能够减轻使用正则表达式的语法包袱。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注