Perl 文本处理入门
FreeGuideOnline
14阅读
2026-07-11
bash perl script.pl
执行单行命令:
```bash
perl -e 'print "Hello, Perl!\n";'
基础字符串与打印
Perl 的语法松弛而强大。字符串可以用单引号或双引号,双引号支持转义字符和变量内插。
my $name = "世界";
print "你好,$name!\n"; # 输出:你好,世界!
print '你好,$name!\n'; # 输出:你好,$name!\n(单引号不解析)
常用输出函数:
print:普通输出,不自动换行say:自动换行输出,需使用use feature 'say';或use v5.10;
文件读写:文本处理的第一步
读取整个文件
use strict;
use warnings;
my $filename = "data.txt";
open(my $fh, '<', $filename) or die "无法打开文件 '$filename': $!";
my @lines = <$fh>; # 将文件所有行读入数组
close($fh);
foreach my $line (@lines) {
print $line; # 逐行输出
}
逐行读取(节省内存)
while (my $line = <$fh>) {
chomp($line); # 去掉行尾换行符
# 处理 $line
}
写入文件
open(my $out_fh, '>', 'output.txt') or die $!;
print $out_fh "这是第一行\n";
print $out_fh "这是第二行\n";
close($out_fh);
快速单行处理
Perl 命令行提供便利的 -n 和 -p 选项,自动遍历输入并执行代码。
# 打印文件每一行(类似 cat)
perl -ne 'print' data.txt
# 给每一行加行号后输出
perl -ne 'print "$. $_"' data.txt
# 将文件中的所有 "foo" 替换为 "bar" 并写回
perl -pi -e 's/foo/bar/g' data.txt
正则表达式:Perl 的看家本领
正则表达式是文本处理的核心,Perl 提供 =~ 操作符用于匹配、替换和转换。
匹配
my $str = "hello123world";
if ($str =~ /(\d+)/) {
print "找到数字: $1\n"; # 输出: 找到数字: 123
}
常用匹配修饰符:
/i:忽略大小写/g:全局匹配(用于替换时全部替换)/m:多行模式,^和$匹配行首行尾/s:点号匹配包括换行符
替换
my $text = "I love Perl. Perl is great.";
$text =~ s/Perl/Python/r; # 只替换第一个,/r 返回新字符串不修改原值
$text =~ s/Perl/Python/g; # 全局替换
捕获组与后向引用
# 交换单词顺序
my $name = "John Doe";
$name =~ s/(\w+)\s+(\w+)/$2, $1/;
print $name; # 输出: Doe, John
常用正则模式速查
| 模式 | 含义 |
|---|---|
\d |
数字 [0-9] |
\w |
单词字符 [a-zA-Z0-9_] |
\s |
空白字符(空格、制表等) |
. |
除换行外的任意字符 |
* |
零次或多次 |
+ |
一次或多次 |
? |
零次或一次 |
{n,m} |
n 到 m 次 |
^ |
字符串或行首 |
$ |
字符串或行尾 |
内置函数:split、join、grep、map
split —— 字符串分割
my $csv = "apple,banana,grape";
my @fruits = split /,/, $csv; # 得到数组 ('apple', 'banana', 'grape')
按空白分割(保留单词):
my $line = " hello world ";
my @words = split ' ', $line; # 自动处理前后空格,结果 ('hello', 'world')
join —— 数组连接
my @parts = ("2024", "12", "25");
my $date = join "-", @parts; # "2024-12-25"
grep —— 从列表中筛选
grep 与 Linux 的同名命令不同,它是一个函数,用于过滤列表元素。
my @numbers = (1, 2, 3, 4, 5, 6);
my @even = grep { $_ % 2 == 0 } @numbers; # 得到 (2, 4, 6)
结合正则:
my @lines = ("error: disk full", "info: start", "error: timeout");
my @errors = grep { /error/ } @lines;
map —— 转换列表
将每个元素按照块或表达式变换,返回新列表。
my @nums = (1, 2, 3);
my @squared = map { $_ * $_ } @nums; # (1, 4, 9)
# 提取文件中每行的第一个字段
my @first_fields = map { (split)[0] } <$fh>;
实战案例:典型文本处理任务
1. 分析 Nginx 日志,统计访问量最高的 IP
假设日志格式类似:
192.168.1.1 - - [25/Dec/2024:10:00:00 +0800] "GET /index.html HTTP/1.1" 200 ...
取出 IP 并计数:
my %count;
while (<>) {
if (/^(\S+)/) { # \S+ 匹配非空白字符,即 IP
$count{$1}++;
}
}
# 按频次降序输出
foreach my $ip (sort { $count{$b} <=> $count{$a} } keys %count) {
print "$ip 访问了 $count{$ip} 次\n";
}
运行时将日志文件作为输入:
perl analyze.pl access.log
2. CSV 数据清洗
将文件中的空字段替换为 "N/A",并去除每行末尾的多余逗号。
while (<>) {
s/,,/,N\/A,/g; # 将连续逗号替换为 ,N/A,
s/,$/,N\/A/; # 行尾单独的逗号
s/,\s*$/,N\/A/; # 处理可能存在的尾随空白
print;
}
3. 多行文本合并(例如:每三行合并为一行)
my $line_count = 0;
my @buffer;
while (<>) {
chomp;
push @buffer, $_;
$line_count++;
if ($line_count == 3) {
print join(", ", @buffer), "\n";
@buffer = ();
$line_count = 0;
}
}
# 处理剩余不足三行的情况
if (@buffer) {
print join(", ", @buffer), "\n";
}
4. 提取 HTML/XML 中的标签内容(简单场景)
my $html = '<title>Perl入门教程</title>';
if ($html =~ /<title>(.*?)<\/title>/) {
print "标题是: $1\n";
}
注意:复杂 HTML 建议使用专门的解析模块(如 HTML::Parser),正则不是最佳选择。
常用命令行单行示例
# 反转文件每一行中的字符
perl -lne 'print scalar reverse $_' file.txt
# 统计文件字数,类似 wc
perl -lne 'END {print $words} $words += scalar split' file.txt
# 删除所有空行并输出
perl -ne 'print unless /^$/' file.txt
# 将制表符替换为空格
perl -pe 's/\t/ /g' file.txt
# 打印第10到第20行
perl -ne 'print if 10..20' file.txt
调试与最佳实践
- 始终启用 strict 和 warnings
在脚本开头添加:use strict; use warnings;