添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
光明磊落的镜子  ·  GORM ...·  1 年前    · 
开心的海豚  ·  python ...·  2 年前    · 
发财的蛋挞  ·  JavaScript ...·  2 年前    · 

正则表达式:批量移除修改版论文颜色标记

0 学习动机:LaTeX代码批量替换

在论文修改时,往往会在修改处使用颜色标记,比如:

模型预测控制是\color{blue}{世界上}最好的控制方法。

对应的LaTeX代码为:

模型预测控制是{\color{blue}世界上}最好的控制方法。

但修改完成后,手动移除这些颜色标记费时费力。

右大括号的位置太难以捉摸了!

能否借助正则表达式,将这些蓝色标记批量移除呢?

即能否使用正则表达式将 \text{\{\\color\{blue\} * \}} 批量替换为 \text{*} 呢?

今天我来学习一下正则表达式,并尝试解决这个问题。

1 正则表达式简单学习

1.0 正则表达式学习资源

目前网络上有很多优秀的正则表达式教程:

学习过程中,可以使用正则表达式在线测试工具:

1.1 正则表达式简介

正则表达式(Regular Expression)是一个字符串,用于匹配符合某个规则的字符串。

正则表达式可以用来:

  • 验证字符串是否符合某种规则(数据验证)
  • 查找和替换符合规则的字符串(查找替换)

正则表达式分为普通字符和元字符,元字符可以构建复杂的匹配规则。

1.2 正则表达式元字符

\ 转义下一个字符

| 或 c(a|b)t匹配cat,cbt

^ 匹配字符串的开始位置 ^a不会匹配cat

$ 匹配字符串的结束位置 a$不会匹配cat


{m} 前面字符出现m次

{m,} 前面字符至少出现m次

{m,n} 前面字符出现m到n次

+ 前面字符出现1次或多次 cat+匹配cat,catt

? 前面字符出现0次或1次 cat?匹配ca,cat

* 前面字符出现任意次 cat*匹配ca,cat,catt

? 在以上元字符后面,指尽可能少匹配 a+?匹配aa中第一个a


() 定义运算优先级和范围 c(at)?匹配c,cat

[] 匹配括号内所有字符 [a]匹配cata中的两个a

[^] 匹配除了括号内所有字符 [^a]匹配cata中的c,t

[-] 匹配除了括号内所有字符 [A-Z]匹配所有大写字母

. 匹配除换行符的所有字符


\b单词边界\B非单词边界 \d数字\D非数字

\f换页\n换行\r回车 \t制表\v垂直制表

\s空白\S非空白 \s=[\f\n\r\t\v]

1.3 正则表达式预查

(?:pattern) 非获取匹配

(?=pattern) 正向肯定预查

(?!pattern) 正向否定预查

(?<=pattern) 反向肯定预查

(?<!pattern) 反向否定预查

2 批量移除论文蓝色修改标记

2.0 有bug的现有方案

知乎上已经有该问题的解答,但是有bug:

其构造的正则表达式为: \{\\color\{purple\}(.*?)\} ,并将相应文本替换成 $1

(注:$num代表第num个分组的匹配内容)

正如原文作者所说,使用该方法,不能处理有嵌套的括号的情况:

2.1 失败的正则表达式堆栈

参考这篇博客:

构造替换正则表达式:

{\s*\\color\s*{purple}([^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*)}

但堆栈并不能正常工作,使用这种方法将会在有嵌套括号的情况下,直接匹配到文本最后一个右括号:

我还尝试了 正则表达式30分钟入门教程 中的“平衡组/递归匹配”,这时候Sublime直接报错了,合理怀疑Sublime对堆栈的支持并不好。

教程中也提到:“这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法”

2.2 不含有嵌套括号的匹配

于是,我放弃了使用堆栈,这就意味着不能处理无限嵌套的括号。

先搞一个没有嵌套括号的正则表达式: {\s*\\color\s*{purple}\s*([^{}]*)}

成功了!正则表达式仅匹配了不含有嵌套括号的文本:

2.3 含有单层嵌套括号的匹配

只需要在没有嵌套括号的基础上,增加任意次仅有单层括号的匹配即可。

构造正则表达式如下:正则表达式: {\s*\\color\s*{purple}\s*[^{}]*([^{}]*{[^{}]*}[^{}]*)*[^{}]*}

又成功了!正则表达式匹配了最多含有单层嵌套括号的文本:

2.4 含有多层嵌套括号的匹配

手动套娃几层,构造匹配最多含有3层嵌套括号的正则表达式:

{\s*\\color\s*{purple}\s*([^{}]*({[^{}]*({[^{}]*({[^{}]*}[^{}]*)*}[^{}]*)*}[^{}]*)*)}

完美,完全匹配了!

2.5 成功解决方案

一般文章中的括号嵌套层数是有限的,因此列举了一些,各位按需取用(记得修改颜色):

不含有内嵌括号: {\s*\\color\s*{purple}\s*([^{}]*)}

最大3层内嵌括号: {\s*\\color\s*{purple}\s*([^{}]*({[^{}]*({[^{}]*({[^{}]*}[^{}]*)*}[^{}]*)*}[^{}]*)*)}

最大5层内嵌括号: {\s*\\color\s*{purple}\s*([^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*)}

最大10层内嵌括号: {\s*\\color\s*{purple}\s*([^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*({[^{}]*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*}[^{}]*)*)}

再多的请自行使用如下matlab代码生成吧~

% gen_regex(color, inner nesting num)
gen_regex('blue',30)
function str=gen_regex(color,n)
str=['{\s*\\color\s*{', ...