Perl 正则表达式替换文本

第一次接触”驼”语言,它的正则确实很强。

模式

Perl的正则表达式的三种形式,分别是匹配,替换和转化:

  • 匹配:m//(还可以简写为//,略去m)
  • 替换:s///
  • 转化:tr///

这里的 / 是界定符,并不是固定的,比如有表达式正好出现/,那界定符可改为 #或其他字符。
这个规则在 sed 里也适用,例如:sed 's#hello#world#' hello.txt

  • =~ 表示相匹配
  • !~ 表示不匹配

模式匹配修饰符

修饰符 描述
i 忽略模式中的大小写
m 多行模式
o 仅赋值一次
s 单行模式,”.”匹配”\n”(默认不匹配)
x 忽略模式中的空白
g 全局匹配
cg 全局匹配失败后,允许再次查找匹配串

替换操作修饰符

修饰符 描述
i 如果在修饰符中加上”i”,则正则将会取消大小写敏感性,即”a”和”A” 是一样的。
m 默认的正则开始”^”和结束”$”只是对于正则字符串如果在修饰符中加上”m”,
那么开始和结束将会指字符串的每一行:每一行的开头就是”^”,结尾就是”$”。
o 表达式只执行一次。
s 如果在修饰符中加入”s”,那么默认的”.”代表除了换行符以外的任何字符将会变成任意字符,也就是包括换行符!
x 如果加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。
g 替换所有匹配的字符串。
e 替换字符串作为表达式

Demo

使用Perl将文件中所有的MathJax标签替换为$,并输出到指定文件:

输入参数

  • $ARGV[0] 代表输入
  • $ARGV[1] 代表输出

    文件IO

    为一次性加载全部文件内容,安装 Path:Tiny模块

    1
    2
    perl -MCPAN -e shell
    install Path:Tiny


    perl -MCPAN -e 'install Path:Tiny'

  • 读取:

    1
    2
    use Path::Tiny;
    my $all_of_it = path($ARGV[0])->slurp;
  • 写入:

    1
    2
    open(DATA, ">".$ARGV[1]) or die "file.txt 文件无法打开, $!";
    print DATA $all_of_it;

正则替换

1
2
$all_of_it =~ s#<script type="math/tex; mode=display".*?>(.*?)</script>#\n\$\$\n\1\n\$\$\n#sg;
$all_of_it =~ s#<script type="math/tex".*?>(.*?)</script>#\$\1\$#sg;
  • s 替换模式
  • 将展示模式的MathJax,替换为 $$exp$$ 形式
  • 将单行模式的MathJax,替换为 $exp$ 形式
  • sg 替换修饰符,.匹配所有字符、替换所有匹配的字符串

测试

input.txt

1
2
3
<script type="math/tex; mode=display" id="MathJax-Element-50">\begin{equation}
f'(c)=\frac{f(b)-f(a)}{b-a}.\tag2
\end{equation}</script>

demo.pl

1
2
3
4
5
6
7
8
9
#!/usr/bin/perl
use Path::Tiny;
my $all_of_it = path($ARGV[0])->slurp;
$all_of_it =~ s#<script type="math/tex; mode=display".*?>(.*?)</script>#\n\$\$\n\1\n\$\$\n#sg;
$all_of_it =~ s#<script type="math/tex".*?>(.*?)</script>#\$\1\$#sg;

open(DATA, ">".$ARGV[1]) or die "file.txt 文件无法打开, $!";
print DATA $all_of_it;
close DATA;

command: perl demo.pl input.txt output.txt

output.txt

1
2
3
4
5
6

$$
\begin{equation}
f'(c)=\frac{f(b)-f(a)}{b-a}.\tag2
\end{equation}
$$

总结

  • 相比于 sed gawkperl 明显有更强、更灵活的文本控制力
  • grep的匹配器选项中,可以用 -P, --perl-regexp 选项来使用更强的 PCRE 匹配器

尽管PCRE声称与Perl兼容,但现代版本的Perl和PCRE之间存在足够多的差异,可以认为它们具有不同的正则风味。Perl的最新版本甚至在Perl收录前,从PCRE那复制了,PCRE从别的编程语言那复制的功能,目的是使Perl与PCRE更加兼容。如今,PCRE比Perl更加广泛地使用,因为PCRE是众多库和应用程序的组成部分。

Perl 正则表达式
Perl的命令行参数和ARGV
问下 perl 怎么读取整个文件里的内容(包括所有换行)?
How can I read in an entire file all at once?
各个平台下 Perl 模块安装总结
The PCRE Open Source Regex Library