在字符串中随机大写字母

19
我想随机地将字符串中的每个字母大写或小写。我在使用Python处理字符串方面很新,但我认为由于字符串是不可变的,所以我不能执行以下操作:

我想随机更改一个字符串中的每个字符大小写。我刚开始学习使用Python来处理字符串,但是我认为因为字符串是不可变的,所以我无法执行以下操作:

i =0             
for c in sentence:
    case = random.randint(0,1)
    print("case = ", case)
    if case == 0:
        print("here0")
        sentence[i] = sentence[i].lower()
    else:
        print("here1")
        sentence[i] = sentence[i].upper()
    i += 1
print ("new sentence = ", sentence)

并且得到错误:TypeError: 'str'对象不支持项目分配

但是我还能用什么其他方法吗?


使用另一个容器,比如 list,然后从中创建字符串。或者,逐步创建一个新的字符串。 - juanpa.arrivillaga
你可以随机生成大小写的新字符串。 - Mayank Porwal
6个回答

29
您可以像这样使用生成器表达式与 str.join 一起使用:
from random import choice
sentence = 'Hello World'
print(''.join(choice((str.upper, str.lower))(c) for c in sentence))

示例输出:

heLlo WORLd

列表推导式与join一起使用不是更快吗? - U13-Forward
2
不,列表推导式会更慢,因为它会先实现所有项目值以形成列表,然后再将列表传递给 join,这会导致时间和内存方面的额外开销。使用生成器表达式,join 方法可以简单地遍历生成器输出,因为生成器逐个生成项目值。 - blhsing
2
很好,谢谢你告诉我。 - U13-Forward
9
您说得对。join 需要一个列表作为参数,所以直接给它一个列表比给它一个生成器更快。 来源 - timgeb
1
@timgeb 哦,我是对的,哇,现在我知道了 :-) - U13-Forward
4
@timgeb,那么我承认我的错误。谢谢。 - blhsing

7

构建一个新字符串。

这里提供了一种对您原始代码进行微小更改的解决方案:

>>> import random
>>> 
>>> def randomcase(s):
...:    result = ''
...:    for c in s:
...:        case = random.randint(0, 1)
...:        if case == 0:
...:            result += c.upper()
...:        else:
...:            result += c.lower()
...:    return result
...:
...:
>>> randomcase('Hello Stackoverflow!')
>>> 'hElLo StaCkoVERFLow!'

编辑:删除了我的一行代码,因为我喜欢blhsing的更好。


4
import random
sentence='quick test'
print(''.join([char.lower() if random.randint(0,1) else char.upper() \
                   for char in sentence]))

快速测试


1
你可以将你的列表传递给 join() 来获得更完整的解决方案。 - Ma0
1
尽管这个答案对我来说和@blhsing的答案一样有效,但它的性能稍微差一点。 - Artur Barseghyan

3

只需将字符串实现更改为列表实现。由于字符串是不可变的,因此无法更改对象内部的值。但是Lists可以更改,因此我只更改了你代码中的那一部分。请注意,有更好的方法来完成此操作,请参考这里

import random
sentence = "This is a test sentence" # Strings are immutable
i =0
new_sentence = [] # Lists are mutable sequences
for c in sentence:
    case = random.randint(0,1)
    print("case = ", case)
    if case == 0:
        print("here0")
        new_sentence += sentence[i].lower() # append to the list
    else:
        print("here1")
        new_sentence += sentence[i].upper() # append to the list
    i += 1
print ("new sentence = ", new_sentence)

# to print as string
new_sent = ''.join(new_sentence)
print(new_sent)

2
您可以按以下方式操作:
char_list = []            
for c in sentence:
    ucase = random.randint(0,1)
    print("case = ", case)
    if ucase:
        print("here1")
        char_list.append(c.upper())
    else:
        print("here0")
        char_list.append(c.lower())
print ("new sentence = ", ''.join(char_list))

0

一种不涉及Python循环的方法是将其发送到NumPy并在其上执行矢量化操作。例如:

import numpy as np
def randomCapitalize(s):
    s  = np.array(s, 'c').view('u1')
    t  = np.random.randint(0, 2, len(s), 'u1') # Temporary array
    t *= s != 32 # ASCII 32 (i.e. space) should not be lowercased
    t *= 32 # Decrease ASCII by 32 to lowercase
    s -= t
    return s.view('S' + str(len(s)))[0]
randomCapitalize('hello world jfwojeo jaiofjowejfefjawivj a jofjawoefj')

输出结果为:

b'HELLO WoRlD jFwoJEO JAioFjOWeJfEfJAWIvJ A JofjaWOefj'

这个解决方案对于长字符串来说应该是相当快的。但是这种方法有两个限制:

  • 输入必须全部小写。你可以先尝试使用.lower(),但那在技术上效率较低。

  • 它需要特别注意非a到z字符。在上面的例子中,只处理了空格。

通过替换,您可以同时处理更多的特殊字符。

t *= s != 32

使用

# using space, enter, comma, period as example
t *= np.isin(s, list(map(ord, ' \n,.')), invert=True)

例如:

s = 'ascii table and description. ascii stands for american standard code for information interchange. computers can only understand numbers, so an ascii code is the numerical representation of a character such as'
randomCapitalize(s)

它输出:

b'ascII tABLe AnD descRiptIOn. ascii sTaNds for AmEricAN stanDaRD codE FOr InForMAtION iNTeRCHaNge. ComPUtERS can onLY UNdersTand nUMBers, So An asCIi COdE IS tHE nuMERIcaL rEPrEsEnTATion Of a CHaractEr such as'

嘿,如果有什么问题,我会修复它。你能否至少留下一个评论来说明为什么要点踩呢? - ZisIsNotZis
不是一个downvoter,但我认为问题在于将Numpy和向量化等内容引入到一个只需要学习可变与不可变容器的情况中。 - Sneftel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接