- A+
前几篇文章讲到了百度云盘中文件或文件夹名称的关键词替换等,但是在面对一些复杂的名称需要进行替换时,关键词替换就会无法解决。这时需要使用强大的正则表达进行替换,正则表达式又是什么,如何进行正则替换修改名称呢?
一、复杂名称替换需求
首先问题是这样的,在百度网盘中有很多文件夹的名称带有营销信息,如:爱在灵灵久博客,但是名称并非整齐的显示‘爱在灵灵久博客’七个字,而是这样显示的‘爱a在x灵e灵c久t博8客’或者‘爱1在2灵5灵8久g博r客’等等,也就是是说关键词中插入了一些杂乱信息,如果直接通过关键词查找是找不到的,这时就需要使用到正则表达式进行替换了。
二、什么是正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。几时通过特定的字符来标识某一类的信息,比如:\w 表示匹配字母数字及下划线,\d 表示匹配任意数字,等价于 [0-9],\s 表示匹配任意空白字符,等价于 [\t\n\r\f]等等,像这样类似的字符有很多,后面会单独进行附录。
三、如何进行正则替换
再回到第一节讲到的问题,如何将带有‘爱a在x灵e灵c久t博8客’等名称的文件或文件夹替换成自己需要的名称呢,,如:将杂乱的字母和数字去掉 ,可以这样编写正则表达式:'[A-Za-z]'
那么对应到软件中就是在批量重命名中点击正则替换,并在弹出框中选择正则替换,同时在第一个输入框中填写[A-Za-z]在第二个框中留空 然后点击确定,那么软件就会自动将‘爱a在x灵e灵c久t博8客’替换为‘爱在灵灵久博客’即:去掉了其中的杂乱字符。
当然正则替换还有很多种情况,总体来说较为复杂,需要知道基本的表达式,并进行组合匹配,最好是能够找人帮忙处理。
四、附录基本正则表达式
Python 正则表达式模块 (re) 简介
Python 的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用这一内嵌于 Python 的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。Python 会将正则表达式转化为字节码,利用 C 语言的匹配引擎进行深度优先的匹配。
表 1. 正则表达式元字符和语法
符号 | 说明 | 实例 |
---|---|---|
. | 表示任意字符,如果说指定了 DOTALL 的标识,就表示包括新行在内的所有字符。 | 'abc' >>>'a.c' >>>结果为:'abc' |
^ | 表示字符串开头。 | 'abc' >>>'^abc' >>>结果为:'abc' |
$ | 表示字符串结尾。 | 'abc' >>>'abc$' >>>结果为:'abc' |
*, +, ? | '*'表示匹配前一个字符重复 0 次到无限次,'+'表示匹配前一个字符重复 1次到无限次,'?'表示匹配前一个字符重复 0 次到1次 | 'abcccd' >>>'abc*' >>>结果为:'abccc'
'abcccd' >>>'abc+' >>>结果为:'abccc' 'abcccd' >>>'abc?' >>>结果为:'abc' |
*?, +?, ?? | 前面的*,+,?等都是贪婪匹配,也就是尽可能多匹配,后面加?号使其变成惰性匹配即非贪婪匹配 | 'abc' >>>'abc*?' >>>结果为:'ab'
'abc' >>>'abc??' >>>结果为:'ab' 'abc' >>>'abc+?' >>>结果为:'abc' |
{m} | 匹配前一个字符 m 次 | 'abcccd' >>>'abc{3}d' >>>结果为:'abcccd' |
{m,n} | 匹配前一个字符 m 到 n 次 | 'abcccd' >>> 'abc{2,3}d' >>>结果为:'abcccd' |
{m,n}? | 匹配前一个字符 m 到 n 次,并且取尽可能少的情况 | 'abccc' >>> 'abc{2,3}?' >>>结果为:'abcc' |
\ | 对特殊字符进行转义,或者是指定特殊序列 | 'a.c' >>>'a\.c' >>> 结果为: 'a.c' |
[] | 表示一个字符集,所有特殊字符在其都失去特殊意义,只有: ^ - ] \ 含有特殊含义 | 'abcd' >>>'a[bc]' >>>结果为:'ab' |
| | 或者,只匹配其中一个表达式 ,如果|没有被包括在()中,则它的范围是整个正则表达式 | 'abcd' >>>'abc|acd' >>>结果为:'abc' |
( … ) | 被括起来的表达式作为一个分组. findall 在有组的情况下只显示组的内容 | 'a123d' >>>'a(123)d' >>>结果为:'123' |
(?#...) | 注释,忽略括号内的内容 特殊构建不作为分组 | 'abc123' >>>'abc(?#fasd)123' >>>结果为:'abc123' |
(?= … ) | 表达式’…’之前的字符串,特殊构建不作为分组 | 在字符串’ pythonretest ’中 (?=test) 会匹配’ pythonre ’ |
(?!...) | 后面不跟表达式’…’的字符串,特殊构建不作为分组 | 如果’ pythonre ’后面不是字符串’ test ’,那么 (?!test) 会匹配’ pythonre ’ |
(?<= … ) | 跟在表达式’…’后面的字符串符合括号之后的正则表达式,特殊构建不作为分组 | 正则表达式’ (?<=abc)def ’会在’ abcdef ’中匹配’ def ’ |
(?:) | 取消优先打印分组的内容 | 'abc' >>>'(?:a)(b)' >>>结果为'[b]' |
?P<> | 指定Key | 'abc' >>>'(?P<n1>a)>>>结果为:groupdict{n1:a} |
表 2. 正则表达式特殊序列
特殊表达式序列 | 说明 |
---|---|
\A | 只在字符串开头进行匹配。 |
\b | 匹配位于开头或者结尾的空字符串 |
\B | 匹配不位于开头或者结尾的空字符串 |
\d | 匹配任意十进制数,相当于 [0-9] |
\D | 匹配任意非数字字符,相当于 [^0-9] |
\s | 匹配任意空白字符,相当于 [ \t\n\r\f\v] |
\S | 匹配任意非空白字符,相当于 [^ \t\n\r\f\v] |
\w | 匹配任意数字和字母,相当于 [a-zA-Z0-9_] |
\W | 匹配任意非数字和字母的字符,相当于 [^a-zA-Z0-9_] |
\Z | 只在字符串结尾进行匹配 |
上面提到贪婪匹配和非贪婪匹配请看例子:
1
2
3
4
5
6
7
8
9
10
|
import re #贪婪 ret_greed = re.findall(r 'a(\d+)' , 'a23b' ) print (ret_greed) #非贪婪 ret_no_greed = re.findall(r 'a(\d+?)' , 'a23b' ) print (ret_no_greed) [ '23' ] [ '2' ] |
由于贪婪匹配为尽可能的多匹配所以结果为23 ,有人好奇了,findall是什么鬼 ,请耐心往下看:
re模块
正则表达式使用反斜杠” \ “来代表特殊形式或用作转义字符,这里跟Python的语法冲突,因此,Python用” \\ “表示正则表达式中的” \ “,因为正则表达式中如果要匹配” \ “,需要用\来转义,变成” \ “,而Python语法中又需要对字符串中每一个\进行转义,所以就变成了” \\ “。
上面的写法是不是觉得很麻烦,为了使正则表达式具有更好的可读性,Python特别设计了原始字符串(raw string),需要提醒你的是,在写文件路径的时候就不要使用raw string了,这里存在陷阱。raw string就是用’r’作为字符串的前缀,如 r”\n”:表示两个字符”\”和”n”,而不是换行符了。Python中写正则表达式时推荐使用这种形式。
1、 re.findall(pattern, string[, flags]):
方法能够以列表的形式返回能匹配的子串。先看简单的例子:
1
2
3
4
5
|
import re a = 'one1two2three3four4' ret = re.findall(r '(\d+)' ,a) print (ret) [ '1' , '2' , '3' , '4' ] |
从上面的例子可以看出返回的值是个列表,并且返回字符串中所有匹配的字符串。
2、re.finditer(pattern, string[, flags])
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。 请看例子:
1
2
3
4
5
6
7
8
|
import re p = re. compile (r '\d+' ) for m in p.finditer( 'one1two2three3four4' ): print m.group(), ### output ### # 1 2 3 4 |
3、re.match和re.search
Python提供了两种不同的原始操作:match和search。match是从字符串的起点开始做匹配,而search(perl默认)是从字符串做任意匹配。看个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import re ret_match = re.match( "c" , "abcde" ); #从字符串开头匹配,匹配到返回match的对象,匹配不到返回None if (ret_match): print ( "ret_match:" + ret_match.group()); else : print ( "ret_match:None" ); ret_search = re.search( "c" , "abcde" ); #扫描整个字符串返回第一个匹配到的元素并结束,匹配不到返回None if (ret_search): print ( "ret_search:" + ret_search.group()); ret_match: None ret_search:c |
re.match对象拥有以下方法:
import re a = "123abc456" ret_match= re.match("a","abcde"); print(ret_match.group()) #返回返回被 RE 匹配的字符串 print(ret_match.start()) #返回匹配开始的位置 print(ret_match.end()) #返回匹配结束的位置 print(ret_match.span()) #返回一个元组包含匹配 (开始,结束) 的位置
其中group()方法可以指定组号,如果组号不存在则返回indexError异常看如下例子:
1
2
3
4
5
6
|
import re a = "123abc456" re.search( "([0-9]*)([a-z]*)([0-9]*)" ,a).group( 0 ) #123abc456,返回整体默认返回group(0) re.search( "([0-9]*)([a-z]*)([0-9]*)" ,a).group( 1 ) #123 re.search( "([0-9]*)([a-z]*)([0-9]*)" ,a).group( 2 ) #abc re.search( "([0-9]*)([a-z]*)([0-9]*)" ,a).group( 3 ) #456 |
4、re.sub和re.subn
两种方法都是用来替换匹配成功的字串,值得一提的时,sub不仅仅可以是字符串,也可以是函数。subn函数返回元组,看下面例子:
1
2
3
4
5
6
|
import re #sub ret_sub = re.sub(r '(one|two|three)' , 'ok' , 'one word two words three words' ) #ok word ok words ok words #subn import re ret_subn = re.subn(r '(one|two|three)' , 'ok' , 'one word two words three words' ) #('ok word ok words ok words', 3) 3,表示替换的次数 |