Удаление непечатаемых символов в точки с помощью string.translate()
Так что я делал это раньше, и это удивительный уродливый код для такой, казалось бы, простой задачи.
Цель состоит в том, чтобы перевести любого непечатного персонажа в . (Точка). Для моих целей "печатный" исключает несколько последних символов из 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])))
... который является нечитаемым беспорядком (хотя это работает).
Оттуда вы можете позвонить использовать что-то вроде:
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))
И заманчиво сделать это только для разборчивости.
Тем не менее, я продолжаю думать, что должен быть более элегантный способ выразить это!
4 ответа
Вот другой подход, использующий понимание списка:
filter = ''.join([['.', chr(x)][chr(x) in string.printable[:-5]] for x in xrange(256)])
Широкое использование здесь "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
Я не считаю это решение безобразным. Это, безусловно, более эффективно, чем любое решение на основе регулярных выражений. Вот немного более короткое решение. Но работает только в python2.6:
nonprintable = string.maketrans('','').translate(None, string.printable[:-5])
filter = string.maketrans(nonprintable, '.' * len(nonprintable))
Для реального кода-гольфа, я полагаю, вы бы полностью избегали 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)