正则笔记

June 21st, 2010 Categories: 笔记

笔记三则,贴在这里。

首字母大小写无关模式

有一段时间,我在写正则表达式来匹配Drug关键字时,经常写出 /viagra|cialis|anti-ed/ 这样的表达式。为了让它更美观,我会给关键词排序;为了提升速度,我会使用 /[Vv]iagra/ 而非/viagra/i ,只让必要的部分进行大小写通配模式。确切地说,我是需要对每个单词的首字母进行大小写无关的匹配。

我写了这样的一个函数,专门用来批量转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#convert regex to sorted list, then provide both lower/upper case for the first letter of each word
#luf means lower upper first

sub luf{
    #   split the regex with the delimiter |
    my @arr=sort(split(/\|/,shift));

    #   provide both the upper and lower case for the  
    #   first leffer of each word
    foreach (@arr){s/\b([a-zA-Z])/[\l$1\u$1]/g;}

    #   join the keyword to a regex again
    join('|',@arr);
}

print luf "sex pill|viagra|cialis|anti-ed";
#   the output is:[aA]nti-[eE]d|[cC]ialis|[sS]ex [pP]ill|[vV]iagra

控制全局匹配下次开始的位置

记得jyf曾经问过我,如何控制匹配开始的位置。嗯,现在我可以回答这个问题了。Perl 提供了 pos 函数,可以在 /g 全局匹配中调整下次匹配开始的位置。举例如下:

1
2
3
4
5
$_="abcdefg";
while(/../g)
{
    print $&;
}

其输出结果是每两个字母,即ab, cd, ef

可以使用 pos($_)来重新定位下一次匹配开始的位置,如:

1
2
3
4
5
6
$_="abcdefg";
while(/../g)
{
    pos($_)--;  #pos($_)++;
    print $&;
}

输出结果:

1
2
pos($_)--:  ab, bc, cd, de, ef, fg.
pos($_)++:  ab, de.

可以阅读 Perl 文档中关于 pos的章节获取详细信息。

散列与正则表达式替换

《effective-perl-2e》第三章有这样一个例子(见下面的代码),将特殊符号转义。

1
2
my %ent = { '&' => 'amp', '<' => 'lt', '>' => 'gt' };
$html =~ s/([&<>])/&$ent{$1};/g;

这个例子非常非常巧妙。它灵活地运用了散列这种数据结构,将待替换的部分作为 key ,将与其对应的替换内容作为 value 。这样只要有匹配就会捕获,然后将捕获的部分作为 key ,反查到 value 并运用到替换中,体现了高级语言的效率。

不过,这样的 Perl 代码,能否移植到 Python 中呢? Python 同样支持正则,支持散列(Python 中叫做 Dictionary),但是似乎不支持在替换过程中插入太多花哨的东西(替换行内变量内插)。

查阅 Python 的文档,(在 shell 下 执行 python ,然后 import re,然后 help(re)),:

1
2
3
4
5
6
7
sub(pattern, repl, string, count=0)
    Return the string obtained by replacing the leftmost
    non-overlapping occurrences of the pattern in string by the
    replacement repl.  repl can be either a string or a callable;
    if a string, backslash escapes in it are processed.  If it is
    a callable, it's passed the match object and must return
    a replacement string to be used.

原来 python 和 php 一样,是支持在替换的过程中使用 callable 回调函数的。该函数的默认参数是一个匹配对象变量。这样一来,问题就简单了:

1
2
3
4
5
6
7
8
9
ent={'<':"lt",
    '>':"gt",
    '&':"amp",
    }

def rep(mo):
    return ent[mo.group(1)]

html=re.sub(r"([&<>])",rep, html)

python 替换函数 callback 的关键点在于其参数是一个匹配对象变量。只要明白了这一点,查一下手册,看看该种对象都有哪些属性,一一拿来使用,就能写出灵活高效的 python 正则替换代码。

Tags: , , ,

5 Responses to “正则笔记”

  1. jlake
    June 22nd, 2010 at 09:21
    1

    原来 perl 也可以用哈希表(散列)替换,以前不知道。
    支持回调函数的正则替换更灵活,因为在回调函数里面做任何处理。
    perl 在语言上似乎有些停滞不前。

    [Reply]

    rex Reply:

    或许,但是在正则支持上更加灵活强大。有机会谈一下。

    [Reply]

  2. nihao
    July 17th, 2010 at 10:03
    2

    Rex 你好,我在你的Regex.me上面注册了几个用户了。但是我都没有收到邮箱验证的邮件,用户名是 IloveRegex 和 RegexMan 邮箱都是正确的,也试着过了24小时后再次验证,可是就是收不到邮件验证,到现在我还是不能在网站上面发帖,也没有办法联系上你,要是你看到这篇回复,请再网站的后台把我的用户名设置为通过验证的吧,有什么问题可以联系我的邮箱 748871002@qq.com 谢谢。(还请原谅多次发重复的帖子,为了增加被你看到的可能性)

    [Reply]

    rex Reply:

    欢迎!我手动添加。

    [Reply]

  3. 77k78
    July 18th, 2011 at 07:50
    3

    散列配合js正则,很好,很和谐……

    [Reply]

Leave a Comment

如何在本站贴代码?

可以使用任意语言名称代替“python”.