views:

119

answers:

8

I need to replace a string in case sensitive way. For example

abc -> def
Abc -> Def
aBc -> dEf
abC -> deF

What can I do this with Python?

A: 

The re module is probably what you're looking for. Specifically, the re.sub function can be used for simple string search/replacement.

Rakis
`re.sub` won't keep the original capitalisation of the string. If I understand correctly, the original poster wants to keep the capitalisation.
Tamás
@Tam Ah, after reading the question again I think I misunderstood what he was asking for. If he's looking for effectively a case-insensitive string replacement followed by a "make the case match the previous version" then yeah, `re.sub` isn't going to be the right solution... unless a custom function is passed as the replacement argument. Even then, likely not.
Rakis
A: 

Not the most efficient way, and it's very crude, but probably something like this could work:

def case_insensitive_replace(string, old, new):
    upper_indices = [idx for idx, char in enumerate(string) if char.isupper()]
    replaced = list(string.lower().replace(old.lower(), new.lower()))
    for idx in upper_indices:
        replaced[idx] = replaced[idx].upper()
    return "".join(replaced)
Tamás
+3  A: 
from string import maketrans

"Abc".translate(maketrans("abcABC", "defDEF"))
wilhelmtell
+1 nice and easy
THC4k
This assumes that the same character doesn't appear twice in the input string.
Mark Byers
This won't work for replacing "foo" with "bar" as the "o" character has to be mapped to either "a" or "r" depending on context.
Tamás
+3  A: 

Here's a method using regular expressions. The key point is that when it finds a match it first modifies the replacement string to match the casing of the matched string. This works because re.sub can take a function as a replacement instead of just a string.

import re

def case_sensitive_replace(s, before, after):
    regex = re.compile(re.escape(before), re.I)
    return regex.sub(lambda x: ''.join(d.upper() if c.isupper() else d.lower()
                                       for c,d in zip(x.group(), after)), s)

test = '''
abc -> def
Abc -> Def
aBc -> dEf
abC -> deF
'''

result = case_sensitive_replace(a, 'abc', 'def')
print(result)

Result:

def -> def
Def -> Def
dEf -> dEf
deF -> deF
Mark Byers
+1  A: 

Pythons str.replace is always case sensitive:

print('test abc test'.replace('abc ', ' def'))
print('test Abc test'.replace('Abc ', ' Def'))
print('test aBc test'.replace('aBc ', ' dEf'))
print('test abC test'.replace('abC ', ' deF'))

will print

test def test
test Def test
test dEf test
test deF test

Joschua
A: 

I understand that You want to change the second string case according to the first string. Am i right? So, my solution is the following. String s2 change its case according to the corresponding string s1. The result is storing in s3. One assumption here is the two strings has the same length.

s1 = "AaBb"
s2 = "cdef"
s3 = ""
index = 0
length = len(s1)

while(True):
    if s1[index].isupper():
        temp = s2[index].upper()
    else:
        temp = s2[index].lower()
    s3 = s3 + temp
    index +=1
    if index == length:
        break
print s3
chnet
A: 

Long time lurker, thought I'd post a suggestion here as some of these seem fairly convoluted.

print map(lambda a, b: b.lower() if a.islower() else b.upper(), "aBc", "def")

It does assume both strings are the same length, however you could easily replace the lambda with a proper function and check for None on the first input.

Andrew
A: 

This will work, although you probably want to add some checks that the string lengths are the same:

string1 = "AbcDEFghiJKLmnO"
string2 = "some other text"

string2 = "".join((string2[i].upper() if string1[i].isupper() else string2[i].lower() 
                   for i in range(len(string1))))
Iceman