【问题标题】:Munging non-printable characters to dots using string.translate()使用 string.translate() 将不可打印的字符转换为点
【发布时间】:2009-11-25 23:59:30
【问题描述】:

所以我以前做过这个,对于这样一个看似简单的任务,这是一个令人惊讶的丑陋代码。

目标是将任何不可打印的字符转换为 .(点)。出于我的目的,“可打印”确实排除了 string.printable 中的最后几个字符(换行符、制表符等)。这是为了打印诸如旧的 MS-DOS 调试“十六进制转储”格式之类的东西......或任何类似的东西(额外的空格会破坏预期的转储布局)。

我知道我可以使用string.translate(),要使用它,我需要一个翻译表。所以我为此使用string.maketrans()。这是我能想到的最好的:

filter = string.maketrans(
   string.translate(string.maketrans('',''),
   string.maketrans('',''),string.printable[:-5]),
   '.'*len(string.translate(string.maketrans('',''),
   string.maketrans('',''),string.printable[:-5])))

...这是一个难以理解的混乱(尽管它确实有效)。

从那里你可以调用 use 类似的东西:

for each_line in sometext:
    print string.translate(each_line, filter)

...开心就好。 (只要你不看引擎盖)。

现在,如果我将这个可怕的表达式分成单独的语句,它会更易读:

ascii = string.maketrans('','')   # The whole ASCII character set
nonprintable = string.translate(ascii, ascii, string.printable[:-5])  # Optional delchars argument
filter = string.maketrans(nonprintable, '.' * len(nonprintable))

为了易读性而这样做很诱人。

但是,我一直认为必须有一种更优雅的方式来表达这一点!

【问题讨论】:

  • 你可以在你的循环中使用each_line.translate(filter)
  • 我没有想到“优雅”的标签。 :((而且我看不到如何添加标签)。
  • 如果代码打高尔夫球整个过程(替换所有不可打印的字符)是您的目标,那么您可以使用一个衬垫(假设my_str 是您要翻译的字符串)''.join(list(map(lambda x: ['.',x][x in set(string.printable[:-5])], my_str)) 但是,我可能更喜欢使用:''.join(list(map(lambda x: x if (x in set(string.printable[:-5])) else '.', my_str))) 以提高清晰度

标签: python code-golf


【解决方案1】:

这是使用列表推导的另一种方法:

filter = ''.join([['.', chr(x)][chr(x) in string.printable[:-5]] for x in xrange(256)])

【讨论】:

  • 哦,那是邪恶的!依靠条件的 0/1 数值作为包含“。”的两项列表的索引。和每个字符依次。我喜欢!
  • @JimDennis:解释解决方案的同时称赞它。我更喜欢那个!
【解决方案2】:

在这里最广泛地使用“ascii”,但你明白了

>>> import string
>>> ascii="".join(map(chr,range(256)))
>>> filter="".join(('.',x)[x in string.printable[:-5]] for x in ascii)
>>> ascii.translate(filter)
'................................ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~.................................................................................................................................'

如果我在打高尔夫球,可能会使用这样的东西:

filter='.'*32+"".join(map(chr,range(32,127)))+'.'*129

【讨论】:

    【解决方案3】:

    对于实际的代码高尔夫,我想你会完全避免使用 string.maketrans

    s=set(string.printable[:-5])
    newstring = ''.join(x for x in oldstring if x in s else '.')
    

    newstring=re.sub('[^'+string.printable[:-5]+']','',oldstring)
    

    【讨论】:

    • 正则表达式是打高尔夫球的好答案,但会比翻译慢很多
    • 这个问题不应该被标记为 [code-golf] 如果它不是用来打高尔夫球的 ;) 但我确实有一个偷偷摸摸的怀疑 OP 实际上想要使用 maketrans 的答案。
    • 是的,它可能应该被标记为 elegant 而不是 code-colf ;)
    • 我喜欢带有条件表达式的 .join,虽然我现在不能使用它(我的目标库中有太多仍在运行 Python 2.4.x)。
    【解决方案4】:

    我不觉得这个解决方案难看。它肯定比任何基于正则表达式的解决方案更有效。这是一个更短的解决方案。但只适用于python2.6:

    nonprintable = string.maketrans('','').translate(None, string.printable[:-5])
    filter = string.maketrans(nonprintable, '.' * len(nonprintable))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-10
      • 2019-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多