perlrequick中文版

本文档介绍了Perl正则表达式的快速入门指南,包括简单的单词匹配、使用字符类、匹配选择、分组与提取匹配内容等核心概念,并提供了丰富的示例帮助读者理解。

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

目录

名称

perlrequick - Perl的正则表达式快速入门

描述

本页面能够让你了解并使用Perl中最基本的正则表达式用法.

指南

简单的单词匹配

最简单的正则就是一个单词,或者更通用一点,一个字符序列.一个仅包含某个单词的正则可以匹配包含那个单词的任意字符串:

"Hello World" =~ /World/; # 匹配成功

在这条语句中,World就是一个正则,/World/两边的双斜杠//告诉Perl这是一个正则表达式.运算符=~会把任意的字符串传递给该正则表达式,如果正则匹配成功,则返回真,如果匹配失败,则返回假.在上面的例子中,World刚好匹配了字符串"Hello World"中的第二个单词,所以该表达式返回的值为真.

类似的这种表达式经常会被用在条件判断语句中:

print "It matches\n" if "Hello World" =~ /World/;

还可以使用!~运算符来表示相反的意思,也就是"不匹配":

print "It doesn't match\n" if "Hello World" !~ /World/;

正则表达式中包含的字符串直接量还可以使用变量来代替:

$greeting = "World";
print "It matches\n" if "Hello World" =~ /$greeting/;

如果你要匹配的字符串存放在$_里,则语句中的$_ =~部分可以省略:

$_ = "Hello World";
print "It matches\n" if /World/;

另外,正则默认的分隔符//还可以换成其他任意配对的符号,不过必须要在前面加上'm':

"Hello World" =~ m!World!;   # 匹配成功,分隔符为'!'
"Hello World" =~ m{World}; # 匹配成功,分隔符为'{}'
"/usr/bin/perl" =~ m"/perl"; # 匹配成功,分隔符为'"',斜杠/不再是分隔符,而是正则中的一个普通字符

正则必须要严格匹配目标字符串中的每个字符才算匹配成功:

"Hello World" =~ /world/;  # 不匹配,字符w大小写不同
"Hello World" =~ /o W/; # 匹配成功,空格' '也是一个普通字符
"Hello World" =~ /World /; # 不匹配,字符串末尾没有空格' '

Perl会尽可能早的在字符串最左边发生匹配:

"Hello World" =~ /o/;       # 匹配了'Hello'中的'o'
"That hat is red" =~ /hat/; # 匹配了'That'中的'hat'

在匹配目标字符串的过程中,并不是所有的字符都匹配它们本身.有一些字符,称之为元字符,它们属于正则表达式表示法中的保留字符,拥有特殊意义.元字符一共有下面这些:

{}[]()^$.|*+?\

想要匹配一个元字符本身,可以使用反斜杠来转义这个元字符:

"2+2=4" =~ /2+2/;                       # 匹配失败,+是一个元字符
"2+2=4" =~ /2\+2/; # 匹配成功,\+可以匹配普通的+号
'C:\WIN32' =~ /C:\\WIN/; # 匹配成功
"/usr/bin/perl" =~ /\/usr\/bin\/perl/; # 匹配成功

在最后一个正则中,斜杠'/'前面也必须使用反斜杠转义,因为斜杠已经用作了正则分隔符.

在正则中,不可打印的ASCII字符可以使用转义序列来表示.常用的例子有:用\t来表示一个制表符,用\n来表示一个换行符,用\r来标识一个回车符.除此之外,任意的字节都可以使用八进制转义序列,比如\033,或者16进制转义序列,比如\x1B来表示:

"1000\t2000" =~ m(0\t2)      # 匹配成功
"cat" =~ /\143\x61\x74/ # 匹配成功,使用了ASCII码转义序列

正则在很多表现上类似于用双引号包围的字符串,比如也可以进行变量内插:

$foo = 'house';
'cathouse' =~ /cat$foo/; #匹配成功
'housecat' =~ /${foo}cat/; #匹配成功

在上面所有的这些例子中,只要正则匹配了目标字符串中的某一部分,就可以算作是匹配成功.如果想要限制匹配具体发生的位置,我们可以使用锚点元字符 ^$.锚点^匹配的是字符串的开头位置,锚点$匹配的是字符串的结束位置,或者字符串尾部的换行符之前的位置.下面是一些例子:

"housekeeper" =~ /keeper/;         #匹配成功
"housekeeper" =~ /^keeper/; #匹配失败
"housekeeper" =~ /keeper$/; #匹配成功
"housekeeper\n" =~ /keeper$/; #匹配成功
"housekeeper" =~ /^housekeeper$/; #匹配成功

使用字符类

一个字符类可以匹配一系列可能匹配的字符,而不仅仅是单个字符.字符类使用一个方括号[...]来表示,一系列可能匹配的字符都放在这个方括号里面.下面是一些例子:

/cat/;            # 匹配'cat'
/[bcr]at/; # 匹配'bat','cat',或'rat'
"abc" =~ /[cab]/; # 匹配'a'

在上面最后一条语句中,虽然'c'是字符类中的第一个字符,但该正则最先匹配到的是目标字符串最左边的字符'a' .

/[yY][eE][sS]/; # 忽略大小写匹配'yes',即是'yes','Yes','YES',等.
/yes/i; # 效果同上

第二个正则使用了'i'修饰符,该修饰符的作用是让匹配忽略大小写.

字符类的字符中也有普通字符和特殊字符(元字符)之分,但字符类中的普通字符和特殊字符与字符类外部的不同.字符类中的特殊字符有这些:-]\^$,想要匹配它们本身必须使用反斜杠转义:

/[\]c]def/; # 匹配']def'或'cdef'
$x = 'bcr';
/[$x]at/; # 匹配'bat,'cat',或'rat'
/[\$x]at/; # 匹配'$at'或'xat'
/[\\$x]at/; # 匹配'\at','bat,'cat',或'rat'

在字符类中,特殊字符'-'作为了范围运算符,利用范围运算符,冗长的[0123456789][abc...xyz]可以精简成[0-9][a-z] :

/item[0-9]/;    # 匹配'item0'或...或'item9'
/[0-9a-fA-F]/; # 匹配一个十六进制数字

但如果'-'字符放在了字符类的开头处或末尾处,该字符就会被当作一个普通字符来看待.

字符^只有放在字符类的开头处才算是一个特殊字符,它代表的是否定字符类,效果是让该字符类能够匹配那些所有不在该字符类内部的字符.普通字符类[...]和否定字符类[^...]都必须匹配一个有效的字符,不能什么也不匹配.下面是例子:

/[^a]at/;  # 不匹配'aat'或'at',但匹配其他所有的类似'bat','cat,'0at','%at',等.
/[^0-9]/; # 匹配一个非数值字符
/[a^]at/; # 匹配'aat'或'^at',这里'^'是个普通字符

Perl支持一些常用字符类的简写形式.(下面讲的这些简写形式的意义都得在该正则开启了ASCII安全模式(使用/a修饰符)的前提下才正确,否则这些简写形式也能匹配非ASCII的Unicode字符.查看perlrecharclass文档中的反斜杠序列了解详情.)

  • \d 代表一个数字字符,相当于:

    [0-9]
  • \s 代表一个空白符,相当于:

    [\ \t\r\n\f]
  • \w 代表一个单词字符(字母,数字,下划线),相当于:

    [0-9a-zA-Z_]
  • \D 是\d的否定形式,它代表任何一个非数字字符,相当于:

    [^0-9]
  • \S 是\s的否定形式,它代表任何一个非空白符字符,相当于:

    [^\s]
  • \W 是\w的否定形式,它代表任何一个非单词字符,相当于:

    [^\w]
  • 点号'.'匹配任何一个非换行符"\n"的字符.相当于:

    [^\n]

 \d\s\w\D\S\W这些简写形式可以使用在字符类外部,也可以使用在字符类内部.下面是一些例子:

/\d\d:\d\d:\d\d/; # 匹配hh:mm:ss时间格式
/[\d\s]/; # 匹配任何一个数字或空白符
/\w\W\w/; # 匹配一个单词字符,后跟一个非单词字符,再跟一个单词字符
/..rt/; # 匹配任意两个非换行符的字符,后跟'rt'
/end\./; # 匹配'end.'
/end[.]/; # 同上,匹配'end.'

单词锚点\b匹配一个单词边界,也就是一个单词字符和非单词字符\w\W\W\w中间的那个位置,比如:

$x = "Housecat catenates house and cat";
$x =~ /\bcat/; # 匹配'catenates'中的cat
$x =~ /cat\b/; # 匹配'housecat'中的cat
$x =~ /\bcat\b/; # 匹配字符串结尾处的'cat'

在最后一个例中,字符串结尾处的位置也是一个单词边界.

匹配这个或那个

我们可以使用多选元字符'|'来匹配多个可能的字符序列.比如想匹配dogcat,我们可以用正则dog|cat.和前面一样,Perl会从目标字符串的最左边开始进行匹配.在每个字符处,Perl会首先尝试匹配第一个选项dog.如果dog不匹配,再尝试下一个选项cat.如果cat也不匹配,则匹配失败,Perl会开始尝试目标字符串中的下个字符.下面是一些例子:

"cats and dogs" =~ /cat|dog|bird/;  # 匹配"cat"
"cats and dogs" =~ /dog|cat|bird/; # 匹配"cat"

在第二个正则中,即使dog是第一个选项,但cat还是最先匹配了字符串最左边的cats.

"cats"          =~ /c|ca|cat|cats/; # 匹配"c"
"cats" =~ /cats|cat|ca|c/; # 匹配"cats"

在目标字符串中的某个字符位置处,会优先匹配正则多选分支中的第一个选项,如果匹配成功,则继续匹配下面的正则,如果匹配失败,才尝试下个选项.

分组和层次匹配

分组元字符()可以让正则中的一部分内容被当作一个单元来对待.比如正则house(cat|keeper)会匹配一个house后跟一个catkeeper.下面有更多的例子:

/(a|b)b/;                # 匹配'ab'或'bb'
/(^a|b)c/; # 匹配字符串开头的'ac'或者任意位置的'bc'
/house(cat|)/; # 匹配'housecat'或'house'
/house(cat(s|)|)/; # 匹配'housecats'或'housecat'或'house'.分组也可以嵌套.
"20" =~ /(19|20|)\d\d/; # 匹配了最后一个空选项'()\d\d',因为'20\d\d'不匹配

提取匹配内容

我们还可以利用分组元字符()提取出目标字符串中自己感兴趣的那部分内容.每个分组匹配的内容都会被存储到一个特殊变量$1,$2,等中.可以像普通变量一样使用它们:

# 提取出时,分,秒
$time =~ /(\d\d):(\d\d):(\d\d)/; # 匹配hh:mm:ss格式
$hours = $1;
$minutes = $2;
$seconds = $3;

在列表上下文中,正则的匹配操作会返回一个包含了所有分组对应的匹配变量的列表($1,$2,...).所以我们可以把上面的代码改写为:

($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);

如果正则中存在嵌套分组,则$1对应了最左边的那个左括号所属的分组, $2则对应了第二个左括号所在的分组,等等.也就是说,无论分组有没有嵌套,一个分组的序号是几只看该分组左括号的位置.例如,下面是个比较复杂的正则,分组序号已经标示了出来:

/(ab(cd|ef)((gi)|j))/;
1 2 34

还有一种和匹配变量$1 , $2 , ...相关联的值,称之为反向引用\g1 , \g2 , ... 反向引用是用在正则内部的匹配变量:

/(\w\w\w)\s\g1/; # 寻找字符串中类似'the the'的字符序列

需要注意的是:$1 , $2 , ... 应该只在正则外部使用,\g1 , \g2 , ...应该只在正则内部使用.

重复匹配

可以使用量词元字符?, * , + ,和{}来重复正则中的某一部分内容.量词必须紧跟在一个字符,字符类,或者分组的后面.它们各自的意义如下:

  • a? = 匹配'a'1次或0次

  • a* = 匹配'a'0次或更多次,也就是任意次

  • a+ = 匹配'a'1次或更多次,也就是至少一次

  • a{n,m} = 匹配'a'至少n次,最多m次.

  • a{n,} = 匹配'a'至少n

  • a{n} = 匹配'a'n次,不多不少.

下面是一些例子:

/[a-z]+\s+\d*/;                # 匹配一个至少包含一个字符的单词,后跟一个至少包含一个字符的连续空白符,再跟一个任意长度甚至是0位的数字
/(\w+)\s+\g1/; # 匹配两个任意长度的重复单词
$year =~ /^\d{2,4}$/; # 确保变量year的值是一个2到4位的数字
$year =~ /^\d{4}$|^\d{2}$/; # 这个更准确一点,因为年份不需要3位数字

这些量词总会尽可能多的匹配字符串中的字符.例如:

$x = 'the cat in the hat';
$x =~ /^(.*)(at)(.*)$/; # 匹配完成后,
# $1 = 'the cat in the h'
# $2 = 'at'
# $3 = '' (空匹配)

第一个.*一直匹配到了最后一个at的左边,第二个.*没有字符可以匹配了,所以它匹配了0次.

更多匹配

还有一些关于匹配运算符的东西你需要知道.那就是全局修饰符//g可以让匹配运算符在同一个字符串上匹配多次.在标量上下文中,如果该正则拥有//g修饰符,则在第一次匹配成功后,下次匹配会从目标字符串中上次成功匹配的结束索引位置开始匹配.而且你还可以使用pos()函数读取或修改目标字符串中上次成功匹配的索引位置.比如,下面的例子:

$x = "cat dog house"; # 3个单词
while ($x =~ /(\w+)/g) {
print "Word is $1, ends at position ", pos $x, "\n";
}

打印出:

Word is cat, ends at position 3
Word is dog
, ends at position 7
Word is house
, ends at position 13

一次失败的匹配或者改变目标字符串会重置当前索引位置.如果你不想在匹配失败后重置当前位置,可以使用//c修饰符,也就成了/regex/gc .

在列表上下文中,//g会返回所有的匹配分组,如果正则中没有分组,则返回整个正则的匹配结果组成的列表,比如:

@words = ($x =~ /(\w+)/g);  # matches,
# $word[0] = 'cat'
# $word[1] = 'dog'
# $word[2] = 'house'

搜索和替换

在Perl中,字符串的搜索和替换使用s/regex/replacement/modifiers这样的形式.其中replacement是一个双引字符串,目标字符串中所有被regex匹配的子字符串都会被replacement代替.这里用来关联目标字符串和s///的运算符仍然是=~,如果需要匹配的目标字符串存储在$_中,那么$_ =~可以省略掉.如果匹配成功,s///运算符会返回总共替换的次数,否则返回假.下面是一些例子:

$x = "Time to feed the cat!";
$x =~ s/cat/hacker/; # $x的值变成了"Time to feed the hacker!"
$y = "'quoted words'";
$y =~ s/^'(.*)'$/$1/; # 删除掉单引号,$y的值成了"quoted words"

使用s///运算符,匹配变量$1,$2,等可以直接用在replacement中.如果正则拥有全局修饰符,s///g会搜索并替换掉源字符串中所有的匹配项:

$x = "I batted 4 for 4";
$x =~ s/4/four/; # $x的值成了"I batted four for 4"
$x = "I batted 4 for 4";
$x =~ s/4/four/g; # $x的值成了"I batted four for four"

无损修饰符s///r会让替换的结果作为返回值返回而不会修改原变量中的值:

$x = "I like dogs.";
$y = $x =~ s/dogs/cats/r;
print "$x $y\n"; # 打印出"I like dogs. I like cats."

$x = "Cats are great.";
print $x =~ s/Cats/Dogs/r =~ s/Dogs/Frogs/r =~ s/Frogs/Hedgehogs/r, "\n";
#打印出"Hedgehogs are great."

@foo = map { s/[a-z]/X/r } qw(a b c 1 2 3);
# @foo现在的值为qw(X X X 1 2 3)

求值修饰符s///e会将替换字符串隐式的传入eval{...}来求值,返回的结果才作为最终的替换字符串.下面是一些例子:

# 将字符串中所有的单词都反向拼写
$x = "the cat in the hat";
$x =~ s/(\w+)/reverse $1/ge; # $x的值成了"eht tac ni eht tah"

# 将百分号转换成十进制数

$x = "A 39% hit rate";
$x =~ s!(\d+)%!$1/100!e; # $x的值成了"A 0.39 hit rate"

上面的最后一个例子演示了s///运算符还可以使用其他的分隔符,比如s!!!s{}{},甚至s{}//.如果使用了单引号s''',则正则和替换字符串都会被当作单引字符串,也就不能进行变量内插.

split运算符

split /regex/, string可以将string分割到一个子字符串列表中,然后返回这个列表.参数中的正则表达式可以指定应该拿什么字符序列来分割源字符串string.例如,想将一个字符串分割成多个单个的单词,使用:

$x = "Calvin and Hobbes";
@word = split /\s+/, $x; # $word[0] = 'Calvin'
# $word[1] = 'and'
# $word[2] = 'Hobbes'

分割一个由逗号分割的数字列表,使用:

$x = "1.618,2.718,   3.142";
@const = split /,\s*/, $x; # $const[0] = '1.618'
# $const[1] = '2.718'
# $const[2] = '3.142'

如果分割符使用了空正则//,则源字符串会被分割为一个个的字符.如果正则中包含分组,那么返回的结果列表中还会包含分组中匹配的内容:

$x = "/usr/bin";
@parts = split m!(/)!, $x; # $parts[0] = ''
# $parts[1] = '/'
# $parts[2] = 'usr'
# $parts[3] = '/'
# $parts[4] = 'bin'

因为$x的第一个字符就匹配了分隔符中指定的正则,所以split返回的列表中的第一个元素是个空字符串.

BUGS

无.

相关链接

这仅仅是一个快速入门指南,想要一份更深入的正则表达式教程,请参阅perlretut,以及完整的参考perlre.

作者和版权

Copyright (c) 2000 Mark Kvale All rights reserved.

This document may be distributed under the same terms as Perl itself.

致谢

笔者在此要感谢Mark-Jason Dominus, Tom Christiansen, Ilya Zakharevich, Brad Hughes, 以及Mike Giroux,感谢他们提出了宝贵的意见.

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值