【问题标题】:Replace values in iterable with values of another iterable to the same value将可迭代的值替换为另一个可迭代的值到相同的值
【发布时间】:2016-01-28 03:43:26
【问题描述】:

这是一个复杂的例子,但它显示了我正在尝试做的事情。假设我有一个字符串:

from string import ascii_uppercase, ascii_lowercase, digits
s = "Testing123"

我想将s 中出现在ascii_uppercase 中的所有值替换为“L”代表大写字母,所有出现在ascii_lowercase 中的值都替换为“l”代表小写字母,以及digits 中的所有值用“n”表示数字。

我目前正在做:

def getpattern(data):
    pattern = ""
    for c in data:
        if c in ascii_uppercase: pattern += "L"; continue
        if c in ascii_lowercase: pattern += "l"; continue
        if c in digits: pattern += "n"; continue
        pattern += "?"

但是,这很乏味,需要替换多个列表。我通常更擅长为这样的事情找到地图类型的算法,但我很难过。我不能让它替换任何已经被替换的东西。例如,如果我运行数字 1 并将其替换为“n”,则下一次迭代可能会将其替换为“l”,因为“n”是小写字母。

getpattern("Testing123") == "Lllllllnnn"

【问题讨论】:

  • 您能否提供一个实际示例来说明您正在努力实现的目标?有很多方法可以将一个简单的字符串映射到另一个字符串,但您的实际情况可能会更加受限。控制字符(如 NULL 或 ACK)在 0-255 的序数范围内,即使不可打印,但如果您正在处理 Unicode 字符,则可能需要不同的方法。
  • 选择的答案是理想的。我不相信我需要 Unicode,但如果我需要,我相信我可以让它工作。谢谢!

标签: python algorithm


【解决方案1】:

您可以创建一个转换表,将所有大写字母映射到'L',所有小写字母映射到'l',所有数字映射到'n'。一旦你有了这样的地图,你可以把它传递给str.translate()

from string import ascii_uppercase, ascii_lowercase, digits, maketrans
s = "Testing123"

intab = ascii_uppercase + ascii_lowercase + digits
outtab = ('L' * 26) + ('l' * 26) + ('n' * 10)
trantab = maketrans(intab, outtab)

print s.translate(trantab)

请注意,在 Python 3 中没有 string.maketrans 函数。相反,您从 str 对象str.maketrans() 获取方法。阅读更多关于这个here 和文档here

我不完全确定str.translate() 的内部结构,但我有根据的猜测是映射为每个字符串字符创建了一个长度为 256 的字符串。因此,当它通过您的字符串时,它会将\x00 转换为\x00\x01 转换为\x01 等,但将A 转换为L。这样您就不必检查每个字符是否在您的翻译词典中。我认为盲目地翻译所有没有分支的字符会带来更好的性能。打印''.join(chr(i) for i in range(256)) 进行比较以查看此内容。

【讨论】:

  • 有趣,我以前从未使用过maketrans。 trantab 变量是 256 字节长,而 intab+outtab 长度只有 124。有没有办法解决这种疯狂?好像效率不高。
  • 另外,我可以像示例中那样使用默认值吗?我不介意全部打出来。我可以用 { ascii_uppercase : 'L' .... etc} 创建一个字典并遍历它。但这很高兴知道。
  • @Goodies 我不明白你的默认值是什么意思。我在你的问题中没有看到这样的例子。
【解决方案2】:

它们位于不同的 32 个 ASCII 块中,因此您可以这样做:

>>> ''.join(' nLl'[ord(c) // 32] for c in s)
'Lllllllnnn'

您的示例表明您没有其他角色,但如果您这样做,这应该可以:

>>> s = "Testing123 and .?#!-+ äöüß"
>>> ''.join(' nLl'[ord(c) // 32] if c <= 'z' and c.isalnum() else '?' for c in s)
'Lllllllnnn?lll????????????'

【讨论】:

  • 创造力+1。它们是字符串,但我不能确定它们都是可打印的字符。此外,我无法将它们设置为 ord 值,因为它们可能并不都在该范围内。不过,我应该在 OP 中指定。
  • 我刚刚添加了一个也适用于其他角色的版本。
【解决方案3】:

以防万一您需要处理 unicode 数据:

import unicodedata

cat = {'Lu':'L', 'Ll':'l', 'Nd':'n'}

def getpattern(data):
    return ''.join(cat.get(unicodedata.category(c),c) for c in data)

【讨论】:

    猜你喜欢
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    • 2012-11-23
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 2020-10-11
    相关资源
    最近更新 更多