阅读笔记-精通正则表达式-第2章-入门示例及扩展-2
5. 使用环视功能为数值添加逗号
四种类型的环视:
· 肯定逆序环视 (?<= ......) 子表达式能够匹配左侧的文本
· 否定逆序环视 (?<! ......) 子表达式不能匹配左侧的文本
· 肯定顺序环视 (?= ......) 子表达式能够匹配右侧的文本
· 否定顺序环视 (?! ......) 子表达式不能匹配右侧的文本
对于肯定顺序环视,从左至右查看文本,尝试匹配子表达式,如果能够匹配,就返回匹配成功信息。例如:(?=/d)表示如果当前位置右边的字符是数字则匹配成功。对于肯定逆序环视,从右至左查看文本。
需要注意的是,四种环视匹配的都是位置,而不是某个字符。比如:对于字符串"Jeffrey",表达式"(?=rey)"表示匹配右边是rey的位置,即Jeff与ref之间的位置。对与这个位置,如果使用字符串修改功能,就实现了对字符串的信息添加。
$value =~ s/(?:\d)(?:\d\d\d)+$/,/g 匹配的位置为:左侧是数字,右侧到结束位置数字个数正好是3的倍数。
以数字12345678为例:第一次匹配到2与3之间的位置,12,345678,第二次匹配到5与6之间的位置,12,345,678。
有一种匹配$value =~ s/(\d)(\d\d\d)+$/$1,$2/g,注意这个表达式,第一次匹配到的是12345678这个整个字符串,$1=12,$2=345678,修改后为12,345678,由于第一次直接匹配到了整个字符串,所以匹配结束了,这里与环视的匹配有很大的不同,环视匹配只匹配到那个位置。
6. Text-to-HTML转换
通过这个例子,发现原来正则表达式还可以写的错落有致。代码如下:
$text =<>; # 读取命令行中指定的第一个文件名
$text =~ s/&/&/g; # 把基本的HTML
$text =~ s/</</g; # 字符&、<和>
$text =~ s/>/>/g; # 进行HTML转义
$text =~ s/^\s*$/<p>/mg # 划分段落
# 转换为链接形式
$text =~ s{
\b
# 把地址保存到$1
{
\w[-.\w]* # username
\@
[-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) # hostname
}
\b
}{<a href="mailto:$1">$1</a>}gix
print $text; #最后,显示HTML文本
· $text =~ s/^\s*$/<p>/mg # 划分段落
/g是全局匹配符
/m是增强行锚点,即^和$会从字符串模式切换到逻辑行模式,即对于字符串模式,一个文本只能有一个开始^和一个结束$,但是在逻辑行模式中,其中的每个行都会有各自的开始^和结束$。
· $text =~ s{regex}{replacement}modifier
实际上,Perl支持用户自定义分割符,默认是 s/.../.../,也可以定义为s{...}{...},或者S|...|...|
对于s{...}{...}由于分割符不选取了{},“/”就不再作为分割符了,因此</a>中的“/”就可以直接使用了,不必进行转义了。
· /x修饰符
代码中的正则表达式如果不进行换行就会很长,读起来,注释起来都很麻烦,/x修饰符使得用户能够以“宽松排列”编排这个表达式,增强可读性。而且允许在表达式中出现,以#开头标记的注释。加上/x修饰符后,表达式中的空白字符就都变为“忽略自身”元字符。如果要用普通的空格等字符,可以对其进行转义,不转义的话,就是被忽略的元字符,此外\s总是能够匹配空白字符,这一点是没有变的。
· 总结
由于HTML标签中有很多</a>之类的标签,使用s{...}{...}可以省去对/的转义
当正则表达式很长的时候,/x使得表达式可以换行且可以加入注释
当需要匹配逻辑行的时候,/m使得^和$可以匹配逻辑行的开始和结束。
7. 处理重复单词
要求将每句话中连续重复出现的单词进行高亮显示,并且如果某该行有重复单词出现,在该行的开始标出重复出现单词所在的文件。
while(<>)
{
next unless {
# 匹配一个单词:
\b # 单词的开始位置
( [a-z]+ ) # 单词存储在$1
# 匹配单词后面的任意多个空白字符和/或tag
( # 空白存储在$2
(?:
\s # 空白字符
| # |
<[^>]+> # <TAG>形式的tag
)+ # 至少需要出现一次
)
# 再次匹配第一个单词
(\1\b)
}
# 上面是正则表达式,下面是replacement字符串,然后是修饰符、/i、/g和/x
{\e[7m$1\e[m$2\e[7m$3\e[m}igx
s/^(?:[^\e]*\n)+//mg; # 去掉所有未标记的行
s/^/$ARGV: /mg; # 在每行开头加上文件名
print;
}
· $\ = “.\n”
这里的$\是特殊变量,一起一行是通过换行符决定的,比如\n,这样快模式下,是通过.\n决定的。这样一句话可能跨越多个行。
· while(<>)和print
<>能够将字符串赋值给一个特殊的变量,并且这个变量保存了s/.../...和print作用的默认字符串 。
· next unless代表如果当前代码块没有执行,代码块下面的代码也不必执行,类似于if() {} else continue;(C++中)
· {\e[7m$1\e[m$2\e[7m$3\e[m}igx
\e[7m是高亮字符的起始标记,\e[m是高亮字符的终止标记。
· s/^(?:[^\e]*\n)+//mg;
由于有重复单词的行中都嵌入了高亮标记代码,这里只要找到没有高亮标记的行,然会替换为空就可以实现删除没有重复单词的行乐。
· s/^/$ARGV: /mg; # 在每行开头加上文件名
ARGV提供了输入文件的名字
· 总结
代码直接来自书中,实际能否正常运行没有实际测试,不能保证。不过代码本身介绍了很多的知识,尤其是/m、/x修饰符,加上以前的/g、/i修饰符,对正则表达式的了解加深了。
8. 总结
第二章通过一些例子,展示了很多正则的具体内容,对PERL也进行了一定的介绍。现在学到了很多知识:元字符含义,转义,$text =~ m/.../.../... $text =~ s/.../.../...,修饰符:/i、/g、/m、/x,环视功能等等。