Python字符串替换除了第一个字符

时间:2015-06-09 19:11:48

标签: python string

编写一个函数,用*替换字符串第一个字母的每个重复字符除了第一个字母本身 - 是否有更多的pythonic /优雅方式来做这个(列表等?)?

def specialreplace(s):
    firstchar = s[0]
    modifiedstr = s[1:].replace(firstchar, "*")
    print firstchar + modifiedstr

specialreplace('oompaloompa') ---> o*mpal**mpa

8 个答案:

答案 0 :(得分:5)

这是一个简单的问题,我不确定你为什么要试图让它复杂化。你的解决方案看起来不错,除了你应该使用.join()而不是' +'将字符串连接在一起。

"".join((s[0], s[1:].replace(s[0], "*"))

答案 1 :(得分:2)

这不是推荐的方法,除非你反复这样做(对于每个字母,多次),但另一种方法是这样做:

我的速度错了。在Python3中也有所不同。

import string
a = 'ababc'
firstchar = a[0]
trantab = string.maketrans(firstchar, '*')

def translate(mystr, firschar):
    trantab = string.maketrans(firstchar, '*')
    return firstchar + string.translate(mystr[1:], trantab)

def translate_iter(mystr, firschar, trantab):
    return firstchar + string.translate(mystr[1:], trantab)

def replace(mystr, firstchar):
    return firstchar + mystr[1:].replace(firstchar, '*')

In [29]: %timeit translate(a, firstchar)
1000000 loops, best of 3: 582 ns per loop

In [30]: %timeit replace(a, firstchar)
1000000 loops, best of 3: 240 ns per loop

In [32]: %timeit translate_iter(a, firstchar, trantab)
1000000 loops, best of 3: 376 ns per loop

编辑:不要在字符串上使用连接。没有理由。

import dis
In [36]: def add(a,b):
    return a+b
   ....: 

In [37]: def join(a,b):
    return join((a,b))
   ....: 

In [42]: dis.dis(add)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 BINARY_ADD          
              7 RETURN_VALUE        

In [43]: dis.dis(join)
  2           0 LOAD_GLOBAL              0 (join)
              3 LOAD_FAST                0 (a)
              6 LOAD_FAST                1 (b)
              9 BUILD_TUPLE              2
             12 CALL_FUNCTION            1
             15 RETURN_VALUE 

您正在招致无意义的函数调用,这使得代码的可读性降低,整体性能降低。

我为牺牲可读性而牺牲了性能,但是当它牺牲性能和可读性时却没有。

答案 2 :(得分:2)

您可以使用枚举:

print("".join(["*" if s[i] == s[0] and i != 0 else ch for i, ch in enumerate(s)]))

但这只是为了好玩,我会坚持使用你自己的解决方案。

要回答您的评论,您可以使用多个映射来使用translate替换多个字符:

from string import maketrans
print(s[0]+s[1:].translate(maketrans(s[0]+s[2]+s[3],"*$!")))
o*$!al**$!a

在python3中,你需要一个使用每个字符的ord作为键的表:

print(s[0]+s[1:].translate((dict(zip((ord(s[0]),ord(s[2]),ord(s[3])),"*$!")))))
o*$!al**$!a

你也可以使用re.sub忽略第一个字符:

s = 'oompaloompa'

from re import sub

print(sub(r"(?<!^)"+s[0], "*", s))
o*mpal**mpa

但又有点矫枉过正。

答案 3 :(得分:1)

您已经在使用列表索引和切片,并且您有一个干净的答案。仍然:

def specialreplace(s):
    chars = [ ('*' if c == s[0] else c) for c in s[1:] ]
    print s[0] + ''.join(chars)

如果你想编写一下这个代码:

specialreplace = lambda s:s[0]+''.join(['*'if c==s[0]else c for c in s[1:]])

使用铲除字典查找并使用默认返回值进行编辑,因为为什么不使用厨房水槽:

specialreplace=lambda s:s[0]+''.join([{s[0]:'*'}.get(c,c)for c in s[1:]])

编辑:@Voo的评论,列表理解是合理的Pythonic - 如果你必须使用SpicyClubSauce所要求的字符列表,那么你就像Python一样接近三元运算符,并加入一个连接字符列表重新组合在一起。 lambda版本非常不顺便。所有这些都不如提问者的原始解决方案那么优雅。

答案 4 :(得分:1)

您的代码看起来很好,我认为可以改进它的一种方法是获得多个索引,为此您可以使用iter函数将字符串转换为支持{{1}的迭代器}:

next

另外,您可以使用列表推导和>>> def specialreplace(s): ... it=iter(s) ... first=next(it) ... return first+''.join(it).replace(first,'*') ... >>> specialreplace(s) 'o*mpal**mpa' 替换replace方法:

join

以下基准测试表明它们之间没有太大区别,但第二种方法更好一点。(对于1000000循环而不是长字符串测试)

def specialreplace(s):
    it=iter(s)
    first=next(it)
    return first+''.join(['*' if i == first else i for i in it])

结果:

from timeit import timeit

s1="""
def specialreplace(s):
    firstchar = s[0]
    modifiedstr = s[1:].replace(firstchar, "*")
    print firstchar + modifiedstr
"""
s2="""
def specialreplace(s):
    it=iter(s)
    first=next(it)
    return first+''.join(['*' if i == first else i for i in it])

    """

s3="""
def specialreplace(s):
    it=iter(s)
    first=next(it)
    return first+''.join(it).replace(first,'*')

    """

print ' first: ' ,timeit(stmt=s1, number=1000000)
print 'second : ',timeit(stmt=s2, number=1000000)                                          
print '3rd : ',timeit(stmt=s3, number=1000000)

答案 5 :(得分:0)

这是使用str.replace()方法执行此操作的pythonic方法:

string_  = 'oompaloompa'
new_string = string_[0]+string_.replace(string_[0],"*",string_.count(string_[0]))[1:

答案 6 :(得分:0)

        Drawable drawable
        if(needBlue){
           drawable = getResources().getDrawable(R.drawable.spin_shape_blue);
        }else{
           drawable = getResources().getDrawable(R.drawable.spin_shape_orange);
        }
        imageView.setImageDrawable(drawable);

答案 7 :(得分:0)

class Coupon(models.Model):
    
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
code = models.CharField(max_length=20)
amount = models.FloatField(max_length=4)
valid_from = models.DateTimeField(null=True)
valid_to = models.DateTimeField(null=True)
max_value = models.IntegerField(validators=[MaxValueValidator(100)], verbose_name='Coupon Quantity', null=True)
used = models.IntegerField(default=0)