HoRain云--Perl正则表达式

🎬 HoRain云小助手:个人主页
🔥 个人专栏: 《Linux 系列教程》《c语言教程》
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
专栏介绍
|
专栏名称 |
专栏介绍 |
|
本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。 |
|
|
本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制! |
|
|
全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。 |
|
|
本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。 |
|
|
本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。 |
|
|
本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等) |
目录

Perl 正则表达式
Perl 的正则表达式(Regular Expressions)是其最强大的功能之一,被誉为"Pattern Matching"的王者。以下是完整的使用指南:
一、基本匹配语法
1. 匹配运算符
| 操作符 | 说明 | 示例 |
|---|---|---|
=~ |
匹配操作符 | $string =~ /pattern/ |
!~ |
不匹配操作符 | $string !~ /pattern/ |
m// |
匹配字面模式 | $string =~ m/pattern/i |
s/// |
替换操作 | $string =~ s/pattern/replacement/g |
tr/// |
字符转换 | $string =~ tr/a-z/A-Z/ |
2. 基础匹配示例
my $text = "Hello, World!";
if ($text =~ /World/) {
print "匹配成功!\n";
}
if ($text =~ /hello/i) { # i: 忽略大小写
print "不区分大小写匹配\n";
}
if ($text !~ /Universe/) { # 不匹配
print "不包含 Universe\n";
}
# 布尔测试
if ("test" =~ /t/) { # true
print "true\n";
}
二、特殊字符与元字符
1. 常见元字符
# ^ - 行首
print "YES" if $str =~ /^Start/;
# $ - 行尾
print "END" if $str =~ /End$/;
# . - 任意单个字符(除换行)
print $& if $str =~ /a.b/; # 匹配 aXb, axb 等
# * - 前一个字符 0 次或多次
print if $str =~ /ab*/; # a, ab, abb...
# + - 前一个字符 1 次或多次
print if $str =~ /ab+/; # ab, abb... (至少一个 b)
# ? - 前一个字符 0 次或 1 次
print if $str =~ /ab?/; # a, ab
# {} - 指定次数
print if $str =~ /a{3}/; # aaa
print if $str =~ /a{2,4}/; # aa, aaa, aaaa
2. 字符集合
# [] - 字符集合
print if $str =~ /[aeiou]/; # 任意元音字母
print if $str =~ /[A-Za-z]/; # 任意英文字母
print if $str =~ /[0-9]/; # 任意数字
print if $str =~ /[^abc]/; # 非 abc 的字符
# \d - 数字 (\[0-9])
print if $str =~ /\d{3}/; # 三位数
# \D - 非数字
print if $str =~ /\D\d\D/;
# \w - 单词字符 ([a-zA-Z0-9_])
print if $str =~ /\w+/; # 连续单词字符
# \W - 非单词字符
print if $str =~ /\W/;
# \s - 空白字符(空格、制表符、换行等)
print if $str =~ /\s/;
# \S - 非空白字符
print if $str =~ /\S/;
# \b - 单词边界
print if $str =~ /\bword\b/; # 完整的 word
# \B - 非单词边界
三、捕获组与反向引用
1. 括号捕获
my $str = "User: Alice, Age: 25";
if ($str =~ /User: (\w+), Age: (\d+)/) {
print "用户名: $1\n"; # Alice
print "年龄: $2\n"; # 25
}
# 使用 named 捕获
if ($str =~ /User: (?<name>\w+), Age: (?<age>\d+)/) {
print $+{name}; # Alice
print $+{age}; # 25
}
2. 后向引用
my $str = "The cat and the cat";
if ($str =~ /(the|a)\1/) { # \1 引用第一个分组
print "存在重复单词\n";
}
# 检查回文
if ($str =~ /^(.)\1$/) { # 两位相同
print "是相同字符对\n";
}
3. 非捕获组
# (?:...) - 非捕获组,提高性能
$color_code =~ /^#(?:(?:[0-9a-f]{6})|(?:[0-9a-f]{3}))$/i;
4. POSIX 命名捕获
my @captures = ("Alice", 25);
$str =~ /User: (?<name>\w+), Age: (?<age>\d+)/;
print "$+{name}, $+{age}\n";
# 同时访问位置和命名
print "$1, $2, $+{name}, $+{age}\n";
四、字符串替换
1. 基本替换
my $str = "Hello World!";
$str =~ s/World/Perl/; # Hello Perl!
print $str;
2. 全局替换
my $str = "foo bar foo baz foo";
$str =~ s/foo/BAR/g; # BAR bar BAR baz BAR
$str =~ s/foo/BAR/gi; # 不区分大小写
$str =~ s/foo/[${^MATCH}_replaced]/gex; # e 执行代码
3. 条件替换
my $str = "Price: 100, Price: 200";
$str =~ s/(\d+)/$1 * 1.1/e; # Price: 110, Price: 220 (e: 执行代码)
my $str = "Low: 50, High: 500";
$str =~ s/(High):/$1: $$$/; # 高价格用三个美元符号标记
4. 分割并重组
my $str = "First Middle Last";
my @parts = split(/ /, $str);
my $new_order = join(" ", reverse(@parts));
五、提取信息
1. List Context 提取所有匹配
my $str = "email: a@x.com, phone: 12345678";
my @emails = $str =~ /([a-z]+@[a-z.]+)/g; # ('a@x.com')
my @numbers = $str =~ /(\d+)/g; # ('12345678')
my %info = $str =~ /(\w+):\s*([^\s]+)/g; # hash key/value pairs
2. 多行匹配
my $text = <<'EOF';
姓名:张三
年龄:25
城市:北京
邮箱:zhang@example.com
姓名:李四
年龄:30
城市:上海
邮箱:li@example.com
EOF
# 匹配所有姓名
my @names = $text =~ /姓名:(.*?)\n/g;
# 匹配整个记录块
while ($text =~ /姓名:(.+?)\n年龄:(.+)\n城市:(.+)\n邮箱:(.+)/g) {
print "$1 - $2岁 - $3 - $4\n";
}
3. 多行模式标志
my $str = "Line 1\nLine 2\nLine 3";
# . 默认不匹配换行,需要 /m 或多行处理
print $& if $str =~ /^Line/m; # 匹配每行的 Line
# /s 让 . 包含换行符
print $& if $str =~ /Line\s.+Line/s;
六、高级特性
1. 条件分支
# 如果存在日期格式就提取年份,否则返回错误
my $str = "Date: 2024-04-27";
$str =~ /(?:Date: )?(?<date>\d{4}-\d{2}-\d{2})?/;
print $+{date} || "无有效日期\n";
2. 前瞻与后顾断言
# 正向前瞻 (lookahead)
print if $str =~ /foo(?=bar)/; # 匹配 'foo' 后面跟着 'bar'
# 负向前瞻
print if $str =~ /foo(?!bar)/; # 匹配 'foo' 后面不是 'bar'
# 正向后顾 (Perl 支持较复杂)
print if $str =~ /(?<=prefix)content/; # prefix 之后的 content
# 负向后顾
print if $str =~ /(?<!prefix)content/; # 不是 prefix 之后的 content
3. 原子组与非回溯
# 原子组 (?> ...) - 不回溯,提高效率
$str =~ /(?>ab)+c/; # 更高效匹配
# 占有量词 (*+, ++, ?+) - 非回溯
$str =~ /a++/; # 尽可能多地匹配 a
4. 递归正则
# 平衡括号(Perl 5.10+)
my $balanced = qr/\((?:[^()]|(?R))*\)/;
$str =~ $balanced; # 匹配嵌套括号
七、内建特殊变量
| 变量 | 说明 |
|---|---|
$& |
最近匹配的文本 |
$1 ~ $99 |
捕获组的内容 |
${^POSTMATCH} |
匹配后的剩余部分 |
${^PREMATCH} |
匹配前的剩余部分 |
$ |
最后一个捕获组的值 |
$ |
最后的捕获位置 |
$" |
列表连接符(未推荐) |
$: |
警告时的文件名 |
$@ |
eval 中的错误信息 |
$ |
正则编译缓存 |
my $str = "Hello World!";
if ($str =~ /(\w+) (\w+)/) {
print "匹配文本:$&\n"; # Hello World
print "第一组:$1\n"; # Hello
print "第二组:$2\n"; # World
print "${^PREMATCH}: 无前置\n";
print "${^POSTMATCH}: 无后续\n";
}
八、性能优化技巧
1. 使用 compiled regex
my $regex = qr/^Hello.*World$/i; # 预编译正则
if ($str =~ $regex) { ... } # 重复使用更高效
2. 避免过度贪婪
# 低效:
$str =~ /(.*)more(.*)/; # 回溯开销大
# 高效:
$str =~ /(.+?)more(.+?)/; # 非贪婪更快速
3. 优先使用简单模式
# 慢:
$str =~ /^[0-9a-fA-F]+\s*$/;
# 快:
$str =~ /^[0-9A-Fa-f ]+\s*$/; # 直接列出范围
4. 避免不必要的锚定
# 总是从开头匹配
$str =~ /^\s*(.*)/; # 每个位置都从 ^ 开始
# 只在必要时使用锚点
$str =~ /value/; # 扫描整个字符串即可
九、实用案例
场景 1:验证邮箱地址
sub validate_email {
my ($email) = @_;
# 简单版本
return $email =~ /^[\w.+-]+\@[\w-]+\.[\w.-]+$/i;
# 严格版本
return $email =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
}
if (validate_email("test@example.com")) {
print "有效的邮箱\n";
}
场景 2:URL 解析
sub parse_url {
my ($url) = @_;
if ($url =~ m{
^(?<scheme>https?://)
(?<host>[^/:]+)
(?::(?<port>\d+))?
(?<path>/.*?)?
(?:\?(?<query>[^#]*))?
(?:#(?<fragment>.+))?
}x) {
return {
scheme => $+{scheme},
host => $+{host},
port => $+{port} || 80,
path => $+{path} || '/',
query => $+{query},
fragment => $+{fragment}
};
}
return undef;
}
my $parsed = parse_url("https://example.com:443/path?query=1");
print $parsed->{host}; # example.com
场景 3:日志分析
sub parse_log_entry {
my ($line) = @_;
# Apache/Nginx 日志格式
if ($line =~ /^(\S+) (\S+) (\S+) \[([^\]]+)\] "(.+)" (\d+) (\d+) "([^"]*)" "(.*)"/) {
return {
ip => $1,
user => $2,
auth => $3,
time => $4,
request => $5,
status => $6,
size => $7,
referer => $8,
agent => $9
};
}
return undef;
}
场景 4:数据清洗
sub clean_text {
my $text = shift;
# 去除多余空白
$text =~ s/\s+/ /g;
# 标准化标点
$text =~ s/[,.!?]+$/,/g;
# 清理特殊字符
$text =~ s/[^[:alnum:][:space:],.]//g;
# 规范化大小写
$text =~ s/\b([a-z])([A-Z])/$1 $2/g;
return $text;
}
# HTML 标签清理
sub strip_html {
my $html = shift;
$html =~ s/<[^>]+>//g; # 移除标签
$html =~ s/ / /gi; # 转义实体
$html =~ s/</</g;
$html =~ s/>/>/g;
return $html;
}
场景 5:JSON 字段提取(简单版)
sub extract_json_value {
my ($json, $key) = @_;
# 注意:生产环境建议用 JSON 模块
my $pattern = "\"$key\"\\s*:\\s*\"([^\"]*)\"";
if ($json =~ /$pattern/) {
return $1;
}
# 数值类型
$pattern = "\"$key\"\\s*:\\s*(\d+\.?\d*)";
if ($json =~ /$pattern/) {
return $1;
}
return undef;
}
十、常用第三方模块
| 模块 | 用途 |
|---|---|
Regexp::Common |
常用正则表达式集合 |
Text::Regex |
扩展正则功能 |
Tree::Regex |
正则表达式树可视化 |
File::Glob |
文件名通配符匹配 |
HTML::Parser |
HTML/XML 解析 |
Regexp::Common 示例
use Regexp::Common;
# 整数
if ($num =~ /^\d+$/) { print "整数\n"; }
# 浮点数
if ($float =~ /^\-?[0-9]*\.[0-9]+$/ or $float =~ /^\-?[0-9]+\.[0-9]*$/ ) {
print "浮点数\n";
}
# URL
if ($str =~ /\Q$RE{ur}{http}/) { print "HTTP URL\n"; }
十一、最佳实践总结
| 原则 | 建议 |
|---|---|
| 可读性 | 使用 /x 标志添加注释和多行 |
| 安全性 | 过滤外部输入,防止注入攻击 |
| 效率 | 预编译正则 qr// |
| 准确性 | 必要时使用锚定 ^ $ |
| 可维护性 | 将复杂正则抽离为子程序 |
| 测试 | 覆盖各种边界情况测试正则 |
/x 标志示例
my $email_re = qr/
[a-zA-Z0-9._%+-]+ # 本地部分
\@ # @ 符号
[a-zA-Z0-9.-]+ # 域名
\. # 点
[a-zA-Z]{2,} # TLD
/x;
掌握这些正则表达式技巧,你就可以在 Perl 中高效地进行文本处理和匹配!
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐




所有评论(0)