The best way to make case insensitive, but match the case of the word that needs to be replaced?

So far I have come up with a method below, but my question is, is there a shorter method that has the same result?

My code is:

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 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 
+7
source share
3 answers

I would use something like this:

 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) 

Output Example:

myStrIngFullOfBaNaNaiWannAReplaCE_BaNaNas

Notes:

  • This handles the case where different matches have different combinations of upper and lower case.
  • It was assumed that the replacement pattern is lowercase (which is very easy to change, anyway).
  • If the replacement pattern is longer than the match, the same case is used as in the pattern.
+5
source

You can pass flags=re.I in re.sub() to the ignore frame

 >>> 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' 
+3
source

From the code it is obvious that the case template for the replacement is made from the case match template, repeating it (like StufF -> BanaNA ). Given this, I will first find the case pattern for the entire string, and then return the string to the desired case:

 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 
+1
source

All Articles