Swap character of string in Python - python

Is there any simple way to swap character of string in python. In my case I want to swap . and , from 5.123.673,682. So my string should become 5,123,673.682.
I have tried:
number = '5.123.673,682'
number = number.replace('.', 'temp')
number = number.replace(',', '.')
number = number.replace('temp', ',')
print(number) # 5,123,673.682
Thanks

One way using dict.get:
mapper = {".": ",", ",":"."}
"".join([mapper.get(s, s) for s in '5.123.673,682'])
Or using str.maketrans and str.translate:
'5.123.673,682'.translate(str.maketrans(".,", ",."))
Output:
'5,123,673.682'

This is a pythonic and clean approach to do that
def swap(c):
if c == ',': return '.'
elif c == '.': return ','
else: return c
number = '5.123.673,682'
new_number = ''.join(swap(o) for o in number)

If you only need to swap single characters, think of it as a mapping instead
def mapping(c):
if c == ',': return '.'
if c == '.': return ','
return c
number = '5.123.673,682'
converted = ''.join(map(mapping, number))
print(converted)
5,123,673.682

Related

pythonic way to replace two character in a string

I have a string ,for example s = "-1+2-3" I want to replace all - to + and all + to -.
what I expected is s = +1-2+3 .So I can't just use s.replace('-','+').replace('+','-'),because it return s=-1-2-3,maybe a for loop can help. But I wonder if there is a pythonic way to do so?
thanks for all solutions i did a simple test for all function below
def a(s="-1+2-3"):
s = re.sub('[+-]', lambda match: '-' if match[0] == '+' else '+', s)
return s
def b(s="-1+2-3"):
PLUS = '+'
MINUS = '-'
swap = {ord(PLUS): ord(MINUS), ord(MINUS): ord(PLUS)}
s = s.translate(swap)
return s
def c(s="-1+2-3"):
replacements = {"+": "-", "-": "+"}
return ''.join([replacements[i] if i in replacements.keys() else i for i in s])
def d(s="-1+2-3"):
return s.replace('+', '\x01').replace('-', '+').replace('\x01', '-')
if __name__ == '__main__':
a = timeit.timeit(a, number=100000) # a=0.20307550000000002
b = timeit.timeit(b, number=100000) # b=0.08596850000000006
c = timeit.timeit(c, number=100000) # c=0.12203799999999998
d = timeit.timeit(d, number=100000) # d=0.033226100000000036
print(f"{a=}\n{b=}\n{c=}\n{d=}\n")
You can use translate (without ord as pointed out by Barmar):
s = "-1+2-3"
s.translate(str.maketrans('-+', '+-'))
Output:
'+1-2+3'
you can use a dictionary and a loop, so you can have any number of replacements in your dictionary.
s = "-1+2-3"
replacements = {"+":"-", "-":"+"}
s = ''.join([replacements[i] if i in replacements.keys() else i for i in s])
'+1-2+3'
You should try:
s=s.replace('+','\x01').replace('-','+').replace('\x01','-')
It replaces all the '+' by an unused character, and then replaces the '-' by '+' and then replaces the "unused characters" by '-', effectivly swapping '+' and '-'.
You can use re.sub().
import re
s = "-1+2-3"
s = re.sub('[+-]', lambda match: '-' if match[0] == '+' else '+', s)
Many have already answered you, so I add this example for completeness using the map() function:
def replaceSymbol(s):
res = s;
if '+' in s:
res = '-'
elif '-' in s:
res = '+'
return res
''.join(map(replaceSymbol, "-1+2-3"))
Output:
+1-2+3

trying to reverse the string with "_" fixed at point

def r(s):
str = []
for i in len(s):
if (s[i]=='_'):
str = s[i] + str
continue
str = s[i] + str
return str
I tried using the above code to convert the following string
Input: ab_cde
Expected Output: ed_cba
s = 'ab_cde'
out = ''
for a, b in zip(s, s[::-1]):
if b != '_' and a != '_':
out += b
else:
out += a
print(out)
Prints:
ed_cba
EDIT: For more fixed points:
s = 'ab_cde_f_ghijk_l'
i, out = iter(ch for ch in s[::-1] if ch != '_'), ''
out = ''.join(ch if ch == '_' else next(i) for ch in s)
print(out)
Prints:
lk_jih_g_fedcb_a
The main idea is to check all the positions of the underscore _, save them and reverse the string without them, to insert them again after reversing.
import re
def r(s):
# check where all the underscore are
underscore_positions = [m.start() for m in re.finditer('_', s)]
# get list of reversed chars without underscores
reversed_chars = [c for c in reversed(s) if c != '_']
# put underscore back where they where
for p in underscore_positions:
reversed_chars.insert(p, '_')
# profit
return "".join(reversed_chars)
The function can be modified to have a different fixed character.
I also uses the package re for the regex function to identify the _, you can do with a simple loop as underscore_positions = [i for i, c in enumerate(s) if c =='_'] if you prefer.
def fixed_reverse(s, ch):
idxs = [-1] + [i for i, x in enumerate(s) if x == ch] + [len(s)]
idxs = [x - i + 1 for i, x in enumerate(idxs)]
chars = "".join(x for x in s if x != ch)[::-1]
return ch.join(chars[a:b] for a, b in zip(idxs[:-1], idxs[1:]))
>>> fixed_reverse("ab_cde_f_ghijk_l", "_")
'lk_jih_g_fedcb_a'
This works by:
Storing the locations of the fixed-point character "_".
Reversing the string with the "_" characters removed.
Inserting the "_" back into the correct locations.

Create a List of characters from string, using only String Functions and not Regular Expressions

Input:
data = "~ddd , eee~, ~aaaa~"
Desired Output:
data = ["~ddd eee~","~aaaa~"]
Print a list of strings from data, that start and end with "~".
Replace , with space if its between ~.
How do i achieve this without using regular expressions in python ?
Not a one-liner, and some stuff may seem redudant, but it's quite plain and understadable.
result = []
opened = False
for i, c in enumerate(data):
if c == '~' and not opened:
start = i
opened = True
elif c == '~' and opened:
end = i + 1
result.append(data[start:end].replace(' , ', ' '))
opened = False
Nice, readable code:
def split_by_ap(word):
i = iter(word.split('~'))
result = []
while True:
space = next(i, None)
word = next(i, None)
if not word: break
result.append(word.replace(',', ''))
return result
print(split_by_ap("~ddd , eee~, ~aaaa~"))
You can use str.split with str.replace:
data = "~ddd , eee~, ~aaaa~"
r = [(i+'~' if i[-1] != '~' else i).replace(', ', '') for i in data.split('~, ')]
Output:
['~ddd eee~', '~aaaa~']

How to change uppercase & lowercase alternatively in a string?

I want to create a new string from a given string with alternate uppercase and lowercase.
I have tried iterating over the string and changing first to uppercase into a new string and then to lower case into another new string again.
def myfunc(x):
even = x.upper()
lst = list(even)
for itemno in lst:
if (itemno % 2) !=0:
even1=lst[1::2].lowercase()
itemno=itemno+1
even2=str(even1)
print(even2)
Since I cant change the given string I need a good way of creating a new string alternate caps.
Here's a onliner
"".join([x.upper() if i%2 else x.lower() for i,x in enumerate(mystring)])
You can simply randomly choose for each letter in the old string if you should lowercase or uppercase it, like this:
import random
def myfunc2(old):
new = ''
for c in old:
lower = random.randint(0, 1)
if lower:
new += c.lower()
else:
new += c.upper()
return new
Here's one that returns a new string using with alternate caps:
def myfunc(x):
seq = []
for i, v in enumerate(x):
seq.append(v.upper() if i % 2 == 0 else v.lower())
return ''.join(seq)
This does the job also
def foo(input_message):
c = 0
output_message = ""
for m in input_message:
if (c%2==0):
output_message = output_message + m.lower()
else:
output_message = output_message + m.upper()
c = c + 1
return output_message
Here's a solution using itertools which utilizes string slicing:
from itertools import chain, zip_longest
x = 'inputstring'
zipper = zip_longest(x[::2].lower(), x[1::2].upper(), fillvalue='')
res = ''.join(chain.from_iterable(zipper))
# 'iNpUtStRiNg'
Using a string slicing:
from itertools import zip_longest
s = 'example'
new_s = ''.join(x.upper() + y.lower()
for x, y in zip_longest(s[::2], s[1::2], fillvalue=''))
# ExAmPlE
Using an iterator:
s_iter = iter(s)
new_s = ''.join(x.upper() + y.lower()
for x, y in zip_longest(s_iter, s_iter, fillvalue=''))
# ExAmPlE
Using the function reduce():
def func(x, y):
if x[-1].islower():
return x + y.upper()
else:
return x + y.lower()
new_s = reduce(func, s) # eXaMpLe
This code also returns alternative caps string:-
def alternative_strings(strings):
for i,x in enumerate(strings):
if i % 2 == 0:
print(x.upper(), end="")
else:
print(x.lower(), end= "")
return ''
print(alternative_strings("Testing String"))
def myfunc(string):
# Un-hash print statements to watch python build out the string.
# Script is an elementary example of using an enumerate function.
# An enumerate function tracks an index integer and its associated value as it moves along the string.
# In this example we use arithmetic to determine odd and even index counts, then modify the associated variable.
# After modifying the upper/lower case of the character, it starts adding the string back together.
# The end of the function then returns back with the new modified string.
#print(string)
retval = ''
for space, letter in enumerate(string):
if space %2==0:
retval = retval + letter.upper()
#print(retval)
else:
retval = retval + letter.lower()
#print(retval)
print(retval)
return retval
myfunc('Thisisanamazingscript')

Python: Count character in string which are following each other

I have a string in which I want to count the occurrences of # following each other to replace them by numbers to create a increment.
For example:
rawString = 'MyString1_test##_edit####'
for x in xrange(5):
output = doConvertMyString(rawString)
print output
MyString1_test01_edit0001
MyString1_test02_edit0002
MyString1_test03_edit0003
MyString1_test04_edit0004
MyString1_test05_edit0005
Assuming that the number of # is not fixed and that rawString is a user input containing only string.ascii_letters + string.digits + '_' + '#, how can I do that?
Here is my test so far:
rawString = 'MyString1_test##_edit####'
incrDatas = {}
key = '#'
counter = 1
for x in xrange(len(rawString)):
if rawString[x] != key:
counter = 1
continue
else:
if x > 0:
if rawString[x - 1] == key:
counter += 1
else:
pass
# ???
You may use zfill in the re.sub replacement to pad any amount of # chunks. #+ regex pattern matches 1 or more # symbols. The m.group() stands for the match the regex found, and thus, we replace all #s with the incremented x converted to string padded with the same amount of 0s as there are # in the match.
import re
rawString = 'MyString1_test##_edit####'
for x in xrange(5):
output = re.sub(r"#+", lambda m: str(x+1).zfill(len(m.group())), rawString)
print output
Result of the demo:
MyString1_test01_edit0001
MyString1_test02_edit0002
MyString1_test03_edit0003
MyString1_test04_edit0004
MyString1_test05_edit0005
The code below converts the rawString to a format string, using groupby in a list comprehension to find groups of hashes. Each run of hashes is converted into a format directive to print a zero-padded integer of the appropriate width, runs of non-hashes are simply joined back together.
This code works on Python 2.6 and later.
from itertools import groupby
def convert(template):
return ''.join(['{{x:0{0}d}}'.format(len(list(g))) if k else ''.join(g)
for k, g in groupby(template, lambda c: c == '#')])
rawString = 'MyString1_test##_edit####'
fmt = convert(rawString)
print(repr(fmt))
for x in range(5):
print(fmt.format(x=x))
output
'MyString1_test{x:02d}_edit{x:04d}'
MyString1_test00_edit0000
MyString1_test01_edit0001
MyString1_test02_edit0002
MyString1_test03_edit0003
MyString1_test04_edit0004
How about this-
rawString = 'MyString1_test##_edit####'
splitString = rawString.split('_')
for i in xrange(10): # you may put any count
print '%s_%s%02d_%s%04d' % (splitString[0], splitString[1][0:4], i, splitString[2][0:4], i, )
You can try this naive (and probably not most efficient) solution. It assumes that the number of '#' is fixed.
rawString = 'MyString1_test##_edit####'
for i in range(1, 6):
temp = rawString.replace('####', str(i).zfill(4)).replace('##', str(i).zfill(2))
print(temp)
>> MyString1_test01_edit0001
MyString1_test02_edit0002
MyString1_test03_edit0003
MyString1_test04_edit0004
MyString1_test05_edit0005
test_string = 'MyString1_test##_edit####'
def count_hash(raw_string):
str_list = list(raw_string)
hash_count = str_list.count("#") + 1
for num in xrange(1, hash_count):
new_string = raw_string.replace("####", "000" + str(num))
new_string = new_string.replace("##", "0" + str(num))
print new_string
count_hash(test_string)
It's a bit clunky, and only works for # counts of less than 10, but seems to do what you want.
EDIT: By "only works" I mean that you'll get extra characters with the fixed number of # symbols inserted
EDIT2: amended code

Categories

Resources