如何解释Python 3.6中的str.maketrans函数?

44
我目前正在参加Udacity的Python编程课程。其中一个项目要求学生重命名照片文件(删除名称中的任何数字),以便将文件按字母顺序排列,然后拼出秘密信息。例如,如果文件名为“48athens”,则程序会尝试删除数字,仅保留“athens”作为文件名。
我使用的是Python 3.6,而课程导师使用的是Python 2.7。为了简化学习过程,我应该使用Python 2.7。但是,现在我仍然会继续使用Python 3.6。
导师重命名文件的方法是使用“.translate”函数,在Python 2.x中需要两个参数,而在Python 3.x中只需要一个参数。它会从文件名中删除任何数字(0到9)。
import os

def rename_files(): #Obtain the file names from a folder.
    file_list = os.listdir(r"C:\Users\Dennis\Desktop\OOP\prank\prank")
    print (file_list)
    saved_path = os.getcwd()
    os.chdir(r"C:\Users\Dennis\Desktop\OOP\prank\prank")
    for file_name in file_list: #Rename the files inside of the folder.
        os.rename(file_name, file_name.translate(None, "0123456789"))
    os.chdir(saved_path)

rename_files()

然而,在Python 3.x中这种方法行不通,因为它会提示:
TypeError: translate() takes exactly one argument (2 given)

谢天谢地,我找到了另一种方法,得到了别人的帮助。然而,我并不确定它是如何工作的。有人能向我解释一下str.maketrans函数吗?以及引号中的前两个空白参数是用来干什么的?我的想法是:对于文件名中的前两个字符,删除任何数字(0到9)。这正确吗?例如,在"48athens"中,如果它们是0到9之间的数字,则删除前两个字符(4和8)。

import os

def rename_files(): #Obtain the file names from a folder.
    file_list = os.listdir(r"C:\Users\Dennis\Desktop\OOP\prank\prank")
    print (file_list)
    saved_path = os.getcwd()
    os.chdir(r"C:\Users\Dennis\Desktop\OOP\prank\prank")
    for file_name in file_list: #Rename the files inside of the folder.
        os.rename(file_name, file_name.translate(str.maketrans('','','0123456789')))
    os.chdir(saved_path)

rename_files()

我的文档理解:

static str.maketrans(x[, y[, z]]) 这个静态方法返回一个可用于str.translate()的翻译表。

它表示传递给str.maketrans的参数以及实际函数str.maketrans将生成一张表,表明“如果出现这个字符,则用这个字符替换它”。然而,我不确定方括号是什么意思。

如果只有一个参数,它必须是一个字典,将Unicode序数(整数)或字符(长度为1的字符串)映射到Unicode序数、字符串(任意长度)或None。然后,字符键将转换为序数。

它表示它只能更改整数或长度为1的字符串中的字符,将其更改为其他整数或字符串(任何长度都可以)。但我认为我有三个参数,而不是一个。

如果有两个参数,它们必须是等长的字符串,在结果字典中,x中的每个字符将被映射到y中相同位置的字符。如果有第三个参数,它必须是一个字符串,其中的字符将在结果中被映射到None。

我有三个参数('', '', '0123456789')。我认为x是第一个'',而y是第二个''。我有第三个参数,它是一个字符串'0123456789',但我不理解将其映射到'None'的含义。


3
你是否阅读了它的文档?https://docs.python.org/3/library/stdtypes.html#str.maketrans - Patrick Haugh
我已经看了好几遍,但是还不太清楚它在说什么。我会编辑我的问题,包括我对文档的理解。 - Dennis
4个回答

76

str.maketrans函数创建一个翻译表,它将整数或字符映射到整数、字符串或None。可以将其视为字典,其中键表示输入字符串中的字符,它们映射到的值表示输出字符串中的字符。

我们遍历要翻译的字符串,并用映射中与之匹配的值替换出现的所有键,如果该值为None,则将其删除。

您可以使用一个、两个或三个参数构建翻译表(我认为这可能是让您感到困惑的原因)。使用一个参数来构建翻译表:

str.maketrans({'a': 'b', 'c': None})

你需要提供一个符合翻译表规则的映射给该函数,它将返回一个相应的等效表格。那些映射到 None 的内容将被删除。

带有两个参数:

str.maketrans('abc', 'xyz')

给定两个字符串。将第一个字符串中的每个字符替换为第二个字符串中相应位置的字符。例如,'a'被映射到'x''b'被映射到'y''c'被映射到'z'

使用三个参数的函数与使用两个参数的函数相同,只是多了一个第三个字符串。

str.maketrans('abc', 'xyz', 'hij')

这与两个参数版本相同,不同之处在于第三个字符串中的字符被移除,就像它们被映射为None一样。 所以你的表格表示“不替换任何内容,但删除在此字符串中出现的字符”。


谢谢,Patrick!这非常有帮助。这是否意味着我示例中的前两个参数“”和“”只是占位符,因为我们不想替换任何内容? - Dennis
1
@Dennis,有效地说,是的。 - Patrick Haugh
我花了一分钟才明白这个,但它非常优雅。向设计API的人致敬。 - Umar.H

9
根据 str.maketrans 文档
如果有第三个参数,它必须是一个字符串,在结果中将被映射为 None
这就是 str.maketrans 所做的事情;它会获取第三个参数中的每个元素,并创建一个映射(Python 字典),将字符串中每个字符的序数值映射到 None
>>> str.maketrans('', '', '0123456789') 
{48: None,
 49: None,
 50: None,
 51: None,
 52: None,
 53: None,
 54: None,
 55: None,
 56: None,
 57: None}

如果存在额外的值作为第一个和第二个参数,它们将作为附加字符添加到此映射中以进行翻译(这就是作者选择''和''的原因;他不希望额外的字符被翻译):
>>> str.maketrans('a', 'A', '0123456789') 
{48: None,
 49: None,
 50: None,
 51: None,
 52: None,
 53: None,
 54: None,
 55: None,
 56: None,
 57: None,
 97: 65}   # map ord('a') to ord('A')

如果你现在将这个应用到你的字符串上,它也会将 'athens' 转换为 'Athens',因为我们提供了额外的 'a', 'A'maketrans。这不是最好的翻译,但足以理解其功能。
然后,str_obj.translate 将对字典中的每个字符执行查找操作,用找到的映射值替换它们。如果在映射中找不到它,则保留原样;如果它是 None,则删除它。这在 str.translate 的文档 中有说明:

当使用 Unicode 码位(整数)进行索引时,表对象可以执行以下任一操作:返回一个 Unicode 码位或字符串,将字符映射到一个或多个其他字符;返回 None,从返回字符串中删除该字符;或者引发 LookupError 异常,将字符映射到它本身。

(强调为作者添加)

谢谢,吉姆!所以单引号之间有空格的前两个参数只是占位符吗?这是否意味着任何数字组合都将被映射为None? - Dennis
前两个空字符串的目的是为了不在映射中创建额外的条目。我已经更新了我的答案以反映这一点,@Dennis。 - Dimitris Fasarakis Hilliard

0
import string
import os
  # Required to call maketrans function.

#trantab = maketrans()
def rename_files():

    x=os.listdir(r'C:\Users\user\Desktop\prank')
    print (x)

    path=os.getcwd()
    print("path is"+path)
    os.chdir(r'C:\Users\user\Desktop\prank')
    for file in x:
        os.rename(file,file.translate(file.maketrans('','','0123456789')))
rename_files()

-4
你可以简单地使用:
str.replace('num', '')  

这将用空字符串替换'1234567890'中的任何数字num,即删除它。


不,那只会导致错误。如果是'number'.replace('num',''),它将返回'ber'。但问题非常明确地要求解释maketrans,而不是提供替代方案。 - Mark Tolonen

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