正则表达式(Perl 示例)

本文深入介绍了Perl正则表达式的使用,包括简单模式匹配、Unicode模式、元字符的运用(如点号、星号、加号、问号、或、方括号)以及模式分组的概念,详细解析了每个特性及其在实际编程中的应用。通过实例展示了如何在字符串中查找、匹配特定模式,对于理解Perl正则表达式具有重要指导意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简单模式

匹配 key 的内容,只要把 key 的内容写在一对斜线 ( / ) 中即可:

$_ = "yabba dabba doo";

if (/abba/) {
    say "It matched the string 'abba'";
}

2. Unicode 模式

a. 匹配包含特定属性的字符

\p{PROPERTY}

匹配属于空白符的字符,包括但不限于 空格,制表符,回车等:

if(/\p{Space}/) {
    say "The string has some whitespace.\n";
}

b. 匹配不包含特定属性的字符(注意这里 P 是大写)

\P{PROPERTY}

3. 元字符

元字符2
点号 (.)匹配任意一个字符
星号(*)匹配前一个条目 零次或多次
加号(+)匹配前一个条目 至少一次
问号(?)匹配前一个条目 零次或一次
反斜线转义
竖线(|)或(OR),择一匹配
方括号([])字符集,只匹配单个字符

a. 点号(.) 是用于匹配任意一个字符的通配符,注意不包括换行符(\n)

$_ = "betty";

if (/bet.y/) {
    say "It matched!";
}

如果只想匹配点号本身,在点号前面加上反斜线转义即可:

$_ = "Mr.Smith";

if (/\./) {
    say "The string has at least a dot.";
}

b. 星号(*) 用来匹配前面的条目零次或者多次。
可以这样理解,星号的符号表示正是数学运算中的乘法(times),可以乘以零次,也可以乘以一二三四五六次等等。
参看下面代码👇:

@_ = qw/ac abc abbc abbbbbbbbbbbbbbc adc/;

foreach (@_) {
    if (/ab*c/) {
    	# 匹配 "ac"、"abc"、"abbc"、"abbbbbbbbbbbbbbc"
    	# 不匹配 "adc"
	    say "$_ matched!";
    }
}

星号(*)前一个条目不仅仅可以是一个字符,也可以是其他元符号,比如点号(.),修改上方代码如下:

foreach (@_) {
    if (/a.*c/) {
        # 字符串 "adc" 也匹配上了
    }
}

c. 加号(+) 匹配前一个条目至少一次。

@_ = ('a.dog', 'a dog', 'a  dog', 'a    dog');

foreach (@_) {
    # 匹配 "a" 和 "dog" 之间用只包含空格的字符串隔开的字符串
    if (/a +dog/) {
        # do something
    }
}

d. 问号(?) 用于匹配前一个条目出现零次或者一次。

@_ = qw/bamm-bamm bammbamm bamm--bamm/;

foreach (@_) {
	# 匹配 'bamm-bamm' 和 'bammbamm'
	# 但不匹配 'bamm--bamm'
    if (/bamm-?bamm/) {
	    # do something
    }
}

e. 或(|) 表示要么匹配左边的内容,要么匹配右边的内容。

$_ = "fred";

if (/fred|barney|betty/) {
    # ...
}

f. 方括号([ ]) ,列出一组可能出现的字符,并匹配其中的一个。
字符集通常不会单独使用,而是作为完整模式的一部分和其他元字符配合使用。

$_ = "The HAL-9000 requires authorization to continue.";

if (/HAL-[0-9]+/) {
    # 匹配至少一个数字
}

注意连字符(-)的使用,在字符集([ ])外它是个普通的字符,所以 “HAL-” 表示普通的短横线,但是在 [0-9] 它表示指定范围。如果需要在字符集中匹配连字符,需要加反斜线 (\):

if (/[+\-*\/]/) {
    # ...
}

字符集搭配脱字符(^)使用,可以指定字符集范围之外的内容。

@_ = qw/an am and arm/;

foreach (@_) {
    if (/a[^nm]/) {
        # 匹配 "arm"
        # 不匹配 "an"、"am" 和 "and"
    }
}

4. 模式分组

星号(*)问号(?)加号(+) 都是针对前一个条目进行匹配的,这里的条目,不仅仅只是字符或者 点号(.),也可以是字符串比如 “abba”。
在正则表达式中用 圆括号(()) 对字符串分组,使之成为一个条目:

@_ = qw/bingbong bingbing bongbong/;

foreach (@_) {
    # 匹配条目 “bing” 零次或者 n 次
    # 这里匹配了 “bingbong” 和 “bongbong”
    # 不匹配 “bingbing”
    if (/(bing)*bong/) {
	    # do something
    }
}

如果想要在表达式中重用条目,可以使用捕获组。对捕获组的引用称为反向引用,表示为 \N ,其中 N 表示组的索引,起始序号为 1。

@_ = ("yabba dabba", "yabbp dabbc", "yabcc dabcc");

foreach (@_) {
    # ‘d’ 后面跟着四个字符
    # 这四个字符跟 ‘y’ 后面的四个字符是一样的
    # 匹配 "yabba dabba", "yabcc dabcc"
    # 不匹配 "yabbp dabbc"
    if (/y(....) d\1/) {
        # do something
    }
}

多个捕获组也是可以的:

@_ = qw/yabba dabba doo/;

foreach (@_) {
    # 匹配 "yabba","dabba"
    # 不匹配 "doo"
    if (/(.)(.)\2\1/) {
	    # do something
    }
}

Perl 5.10 开始支持反向引用的另一种写法 \g{N},这种写法可以很好地消除反向引用与模式直接量部分的二义性:

$_ = "aa11bb";

if (/(.)\111/) {
    # 是 \1,\11 还是 \111 呢?
    # 按照 perl 的逻辑,这里应该是 \111
    # 但是并没有那么多的分组
    # 低版本会直接报错,而高版本则永远无法得到正确的结果
    print "It matched!\n";
}

而采用 \g{N} 的写法,就简单明了多了:

$_ = "aa11bb";

if (/(.)\g{1}11/) {
    # do something
}

\g{N} 写法的另一个好处是可以使用负数,用来指定相对反向引用。

$_ = "xaa11bb";

if (/(.)\g{-1}11/) {
    # ...
}

使用相对方向引用的好处是,如果模式中引用的内容前面需要追加其他内容,那么绝对编号的反向引用会失效,而相对方向的反向引用却不会。

$_ = "xaa11bb";

if (/(.)(.)\g{-1}11/) {
    # 依然可以匹配 "xaa11bb"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值