最佳的无视大小写替换方式,同时匹配要替换词的大小写?
到目前为止,我想出了下面这个方法,但我想问的是,是否还有更简短的方法可以得到相同的结果呢?
我的代码:
input_str = "myStrIngFullOfStUfFiWannAReplaCE_StUfFs"
replace_str = "stuff"
replacer_str = "banana"
print input_str
# prints: myStrIngFullOfStUfFiWannAReplaCE_StUfFs
if replace_str.lower() in input_str.lower(): # Check if even in the string
begin_index = input_str.lower().find( replace_str )
end_index = begin_index + len( replace_str )
replace_section = input_str[ begin_index : end_index ]
case_list = []
for char in replace_section: # Get cases of characters in the section to be replaced
case_list.append( char.istitle() )
while len( replacer_str ) > len(case_list):
case_list += case_list
sameCase_replacer_str = "" # Set match the replacer string's case to the replace
replacer_str = replacer_str.lower()
for index in range( len(replacer_str) ):
char = replacer_str[ index ]
case = case_list[ index ]
if case == True:
char = char.title()
sameCase_replacer_str += char
input_str = input_str.replace( replace_section , sameCase_replacer_str )
print input_str
# prints: myStrIngFullOfBaNaNAiWannAReplaCE_BaNaNAs
3 个回答
1
从代码来看,替换的大小写模式是通过重复匹配的大小写模式来生成的(比如说 StufF -> BanaNA
)。考虑到这一点,我会先找到整个字符串的大小写模式,然后再把字符串调整到想要的大小写:
def to_case(s, cmap):
'returns string cased according to map'
return ''.join([c.upper() if m else c for (c,m) in zip(s,cmap)])
input_str = "myStrIngFullOfStUfFiWannAReplaCE_StUfFs"
replace_str = "stuff"
replacer_str = "banana"
case_map = [c.istitle() for c in input_str] # initial case map
input_str_lower = input_str.lower()
while replace_str.lower() in input_str_lower: # Check if even in the string
ind = input_str_lower.find(replace_str) # find index
cases = [case_map[(ind + i % len(replace_str))] for i in range(len(replacer_str))] # replacement case pattern
case_map = case_map[:ind] + cases + case_map[ind + len(replace_str):]
input_str_lower = input_str_lower.replace(replace_str, replacer_str, 1)
print to_case(input_str_lower, case_map)
# prints: myStrIngFullOfBaNaNAiWannAReplaCE_BaNaNAs
3
你可以在使用 re.sub()
的时候加上 flags=re.I
,这样就可以忽略大小写了。
>>> input_str = "myStrIngFullOfStUfFiWannAReplaCE_StUfFs"
>>> replace_str = "stuff"
>>> replacer_str = "banana"
>>>
>>> import re
>>> from itertools import zip_longest
>>> tr = lambda x, y: ''.join([i[0].upper() if i[1] else i[0].lower() for i in zip_longest(y, [c.isupper() for c in x], fillvalue=(lambda : '' if len(x)>len(y) else x[-1].isupper())())])
>>> re.sub(replace_str, lambda m: tr(m.group(0), replacer_str), input_str, flags=re.I)
'myStrIngFullOfBaNaNaiWannAReplaCE_BaNaNas'
5
我会用这样的方式:
import re
def replacement_func(match, repl_pattern):
match_str = match.group(0)
repl = ''.join([r_char if m_char.islower() else r_char.upper()
for r_char, m_char in zip(repl_pattern, match_str)])
repl += repl_pattern[len(match_str):]
return repl
input_str = "myStrIngFullOfStUfFiWannAReplaCE_StUfFs"
print re.sub('stuff',
lambda m: replacement_func(m, 'banana'),
input_str, flags=re.I)
示例输出:
myStrIngFullOfBaNaNaiWannAReplaCE_BaNaNas
注意事项:
- 这个方法可以处理不同大小写组合的匹配情况。
- 假设替换的内容是小写的(不过这很容易改成其他形式)。
- 如果替换的内容比匹配的内容长,那么会使用替换内容的大小写形式。