🎬 HoRain云小助手个人主页

 🔥 个人专栏: 《Linux 系列教程》《c语言教程

⛺️生活的理想,就是为了理想的生活!


⛳️ 推荐

前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。

专栏介绍

专栏名称

专栏介绍

《C语言》

本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。

《网络协议》

本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制!

《docker容器精解篇》

全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。

《linux系列》

本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。

《python 系列》

本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。

《试题库》

本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等)

目录

⛳️ 推荐

专栏介绍

Perl 正则表达式

一、基本匹配语法

1. 匹配运算符

2. 基础匹配示例

二、特殊字符与元字符

1. 常见元字符

2. 字符集合

三、捕获组与反向引用

1. 括号捕获

2. 后向引用

3. 非捕获组

4. POSIX 命名捕获

四、字符串替换

1. 基本替换

2. 全局替换

3. 条件替换

4. 分割并重组

五、提取信息

1. List Context 提取所有匹配

2. 多行匹配

3. 多行模式标志

六、高级特性

1. 条件分支

2. 前瞻与后顾断言

3. 原子组与非回溯

4. 递归正则

七、内建特殊变量

八、性能优化技巧

1. 使用 compiled regex

2. 避免过度贪婪

3. 优先使用简单模式

4. 避免不必要的锚定

九、实用案例

场景 1:验证邮箱地址

场景 2:URL 解析

场景 3:日志分析

场景 4:数据清洗

场景 5:JSON 字段提取(简单版)

十、常用第三方模块

Regexp::Common 示例

十一、最佳实践总结

/x 标志示例


img

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/&nbsp;/ /gi;             # 转义实体
    $html =~ s/&lt;/</g;
    $html =~ s/&gt;/>/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 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐