日常寫代碼時(shí)候會(huì)遇到一些字符串替換的操作,比如把一大堆"駝峰"形式的字符串批量轉(zhuǎn)換成下劃線形式。"駝峰"形式的變量命名風(fēng)格在Java中很常見,而下劃線形式的變量命名風(fēng)格在C、Python等語言的代碼中更常見一些,兩者沒有嚴(yán)格的好壞區(qū)分。本文就用"駝峰"和"下劃線"相互轉(zhuǎn)換的實(shí)例,講解一下Python的re模塊sub函數(shù)的強(qiáng)大功能。
什么是"駝峰"和"下劃線"風(fēng)格的字符串
變量名、函數(shù)名等標(biāo)識(shí)符的多個(gè)單詞之間用下劃線隔開,這樣的字符串就是下劃線風(fēng)格的字符串,比如:
person_info
ipv6_address
book_id
get_tomorrow_weather()
而駝峰風(fēng)格的字符串就是不同單詞之間用大寫字母進(jìn)行分隔,比如:
personInfo
ipv6Address
bookId
getTomorrowWeather()
re.sub函數(shù)
re.sub函數(shù)是Python內(nèi)置的re模塊的一個(gè)字符串替換函數(shù),支持正則替換。函數(shù)文檔如下:
help(re.sub)
Help on function sub in module re:
sub(pattern, repl, string, count=0, flags=0)
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
re.sub函數(shù)的函數(shù)原型為:sub(pattern, repl, string, count=0, flags=0)
下面簡(jiǎn)單介紹一下每個(gè)參數(shù)的含義:
pattern:是一個(gè)正則表達(dá)式,匹配要替換的子串。repl:可以是一個(gè)字符串,支持對(duì)pattern中分組的后向引用。注意到文檔的最后一句話:
If it is a callable, it's passed the match object and must return a replacement string to be used.
可見,repl也可以是一個(gè)callable對(duì)象(函數(shù)),這個(gè)函數(shù)的入?yún)閜attern正則匹配到的對(duì)象,返回值為一個(gè)字符串,表示要替換成的字符串。
注:正則的分組及后向引用詳見:python正則表達(dá)式系列(4)——分組和后向引用
string:要進(jìn)行替換操作的字符串。count:要替換掉多少個(gè)子串(按從左到右的順序),默認(rèn)值為0,表示替換能被pattern匹配到的所有子串。flags:正則內(nèi)置屬性,默認(rèn)值為0,表示不使用任何內(nèi)置屬性。
注:正則內(nèi)置屬性的用法詳見:python正則表達(dá)式系列(3)——正則內(nèi)置屬性
"駝峰"和"下劃線"字符串之間的相互轉(zhuǎn)換
通過對(duì)re.sub函數(shù)的深入了解,現(xiàn)在應(yīng)該可以輕松寫出"駝峰"和"下劃線"字符串相互轉(zhuǎn)換的代碼了。直接上代碼:
# coding:utf-8
import re
def hump2underline(hunp_str):
'''
駝峰形式字符串轉(zhuǎn)成下劃線形式
:param hunp_str: 駝峰形式字符串
:return: 字母全小寫的下劃線形式字符串
'''
# 匹配正則,匹配小寫字母和大寫字母的分界位置
p = re.compile(r'([a-z]|\d)([A-Z])')
# 這里第二個(gè)參數(shù)使用了正則分組的后向引用
sub = re.sub(p, r'\1_\2', hunp_str).lower()
return sub
def underline2hump(underline_str):
'''
下劃線形式字符串轉(zhuǎn)成駝峰形式
:param underline_str: 下劃線形式字符串
:return: 駝峰形式字符串
'''
# 這里re.sub()函數(shù)第二個(gè)替換參數(shù)用到了一個(gè)匿名回調(diào)函數(shù),回調(diào)函數(shù)的參數(shù)x為一個(gè)匹配對(duì)象,返回值為一個(gè)處理后的字符串
sub = re.sub(r'(_\w)',lambda x:x.group(1)[1].upper(),underline_str)
return sub
代碼中已經(jīng)有詳細(xì)的注釋,還是比較好理解的。下面對(duì)這兩個(gè)函數(shù)進(jìn)行測(cè)試:
def test_hump2underline():
# 供測(cè)試用的一些駝峰形式的字符串
attr1 = 'PersonNamePattern'
attr2 = 'IPv6Address'
attr3 = 'personDetailInfo'
attr4 = 'CCTV'
attr5 = 'CCTVAddress'
attr6 = 'name'
attrs = [attr1,attr2,attr3,attr4,attr5,attr6]
# 遍歷attrs進(jìn)行匹配和轉(zhuǎn)換,把駝峰形式的字符串轉(zhuǎn)成下劃線形式
for attr in attrs:
sub = hump2underline(attr)
print sub
# 輸出:
'''
person_name_pattern
ipv6_address
person_detail_info
cctv
cctvaddress
name
'''
def test_underline2hump():
attr1 = 'person_name_pattern'
attr2 = 'ipv6_address'
attr3 = 'person_detail_info'
attr4 = 'cctv'
attr5 = 'cctvaddress'
attr6 = 'name'
attrs = [attr1, attr2, attr3, attr4, attr5, attr6]
for attr in attrs:
sub = underline2hump(attr)
print sub
# 輸出:
'''
personNamePattern
ipv6Address
personDetailInfo
cctv
cctvaddress
name
'''
JSON字符串字段名的"駝峰"轉(zhuǎn)"下劃線"
JSON是一種非常通用、輕量型的數(shù)據(jù)交換格式,與Python中的字典、Java中的Map具有相同的結(jié)構(gòu)。JSON中的字段名一般需要寫成下劃線的形式,但是有時(shí)候也會(huì)遇到字段名是"駝峰"形式的JSON文本,那么如何把一個(gè)JSON字符串中的所有字段名都從駝峰形式替換成下劃線形式呢?
因?yàn)榭紤]到j(luò)son可能具有多層嵌套的復(fù)雜結(jié)構(gòu),所以下面直接采用正則文本替換的方式進(jìn)行處理,而不是采用把JSON字符串轉(zhuǎn)成字典再進(jìn)行處理。
上代碼:
def json_hump2underline(hump_json_str):
'''
把一個(gè)json字符串中的所有字段名都從駝峰形式替換成下劃線形式。
注意點(diǎn):因?yàn)榭紤]到j(luò)son可能具有多層嵌套的復(fù)雜結(jié)構(gòu),所以這里直接采用正則文本替換的方式進(jìn)行處理,而不是采用把json轉(zhuǎn)成字典再進(jìn)行處理的方式
:param hump_json_str: 字段名為駝峰形式的json字符串
:return: 字段名為下劃線形式的json字符串
'''
# 從json字符串中匹配字段名的正則
# 注:這里的字段名只考慮由英文字母、數(shù)字、下劃線組成
attr_ptn = re.compile(r'"\s*(\w+)\s*"\s*:')
# 使用hump2underline函數(shù)作為re.sub函數(shù)第二個(gè)參數(shù)的回調(diào)函數(shù)
sub = re.sub(attr_ptn,lambda x : '"' + hump2underline(x.group(1)) + '" :',hump_json_str)
return sub
對(duì)上面這個(gè)函數(shù)進(jìn)行測(cè)試:
def test_json_hump2underline():
# 待測(cè)試json字符串
json_str = '''
{
"englishName":"Tom",
"age":18,
"detailInfoTable": {
"address":"USA",
"sportsHobby": ["Basketball","Football","Swimming"],
"contactList":{
"tel" : "1234567",
"emailAddress":"tom@test.com"
}
},
"gender":"male"
}
'''
print json_hump2underline(json_str)
# 輸出:
'''
{
"english_name" :"Tom",
"age" :18,
"detail_info_table" : {
"address" :"USA",
"sports_hobby" : ["Basketball","Football","Swimming"],
"contact_list" :{
"tel" : "1234567",
"email_address" :"tom@test.com"
}
},
"gender" :"male"
}
'''
總結(jié)
經(jīng)過以上實(shí)例可以看出,re.sub函數(shù)因?yàn)橹С至苏齽t替換及回調(diào)函數(shù)替換,在處理復(fù)雜文本替換需求時(shí)具有強(qiáng)大的優(yōu)勢(shì),再一次展現(xiàn)了Python在文本處理領(lǐng)域功能強(qiáng)大又簡(jiǎn)單、易用的特點(diǎn)。