3

Is there a simple, straightforward way to turn this string:

"aBCd3Fg"

Into:

"a**d3*g"

In python 2.7?

Monte Carlo
  • 447
  • 2
  • 6
  • 14

5 Answers5

6

Not sure how fast you need this, but if you're looking for the fastest solution out there. The python string module's translate function is a slightly more roundabout, though generally more performant method:

import string

transtab = string.maketrans(string.uppercase, '*'*len(string.uppercase))
"aBCd3Fg".translate(transtab)

>>>'a**d3*g'

I'm always surprised about how many people don't know about this trick. One of the best guarded secrets in python IMO

Slater Victoroff
  • 21,376
  • 21
  • 85
  • 144
5
import re

print re.sub(r'[A-Z]', '*', "aBCd3Fg")
crazyzubr
  • 1,072
  • 7
  • 14
2
string = ''.join(['*' if x.isupper() else x for x in string])
smac89
  • 39,374
  • 15
  • 132
  • 179
  • Fun fact: If you long for a C-style conditional operator, you can shorten your expression `'*' if r == r.upper() else r` with the equivalent `(r,'*')[r.isupper()]`. – Darren Stone Dec 14 '13 at 04:03
  • @DarrenStone - That will remove the short-circuiting property of the ternary as well as take longer to process. :) –  Dec 14 '13 at 04:05
  • @DarrenStone, I know about this syntax but it is usually frowned upon by most python users. – smac89 Dec 14 '13 at 04:05
  • 1
    @Smac89 - Well said. I'm one of them. :) However, you _can_ improve your code's efficiency by using a list comprehension instead of a generator expression. Here is a [reference](http://stackoverflow.com/a/9061024/2555451). –  Dec 14 '13 at 04:06
  • @Smac89, fair enough. I prefer the terser expression but to each their own. Any reason you wouldn't use `r.isupper()`? – Darren Stone Dec 14 '13 at 04:12
  • @iCodez, thanks. You forced me to check the performance hit. It's longer, for sure, so thanks for the heads-up. `$ python -m timeit "''.join(['*' if x.isupper() else x for x in 'abcDEFhji123'])"` --> `100000 loops, best of 3: 4.07 usec per loop`, while `$ python -m timeit "''.join([(x,'*')[x.isupper()] for x in 'abcDEFhji123'])"` --> `100000 loops, best of 3: 4.93 usec per loop`. – Darren Stone Dec 14 '13 at 04:23
  • The join generator vs list-comp thing is pretty well known. However, I've never seen anyone do the test with a different python implemenation than Cpython. And really, the time difference is pretty negligible. As a matter of style, I prefer the generator, only swapping to the list-comp if I know that this is a bottleneck in the code. – mgilson Dec 14 '13 at 04:30
  • @DarrenStone - You're welcome. In simple terms, the reason your method is slower is that it has to 1) evaluate `r.isupper()`, 2) interpret that evaluation as an integer, 3) build the tuple `(r,'*')`, and 4) index that tuple with the result of `r.isupper()`. The ternary however just evaluates `r.isupper()`. Moreover, the `else r` part will _only_ be run if `if r.isupper()` returns `False`. For more info, see [here](http://stackoverflow.com/questions/394809/ternary-conditional-operator-in-python). –  Dec 14 '13 at 05:18
1

A simple solution :

input = "aBCd3Fg"
output = "".join(['*' if 'A' <= char <= 'Z' else char for char in input ])
#Long version
input = "aBCd3Fg"
output = ''
for char in input:
    output = output + '*' if ord('A') <= ord(char) <= ord('Z') else output + char
print output
-3

You can also do:

for x in myString:
    if (x == 'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'"
        x = '*'

That's a short piece of code that will do the work.

kiasy
  • 304
  • 3
  • 6
  • 17