Изменение непечатаемых символов в точки с помощью string.translate () - PullRequest
2 голосов
/ 26 ноября 2009

Итак, я делал это раньше, и это удивительный уродливый кусок кода для такой, казалось бы, простой задачи.

Цель состоит в том, чтобы перевести любого непечатаемого символа в . (точка). В моих целях «печатный» исключает последние несколько символов из 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 ]

5 голосов
/ 26 ноября 2009

Вот другой подход, использующий понимание списка:

filter = ''.join([['.', chr(x)][chr(x) in string.printable[:-5]] for x in xrange(256)])
4 голосов
/ 26 ноября 2009

Широко используется здесь "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
1 голос
/ 26 ноября 2009

Я не считаю это решение безобразным. Это, безусловно, более эффективно, чем любое решение на основе регулярных выражений. Вот немного более короткое решение. Но работает только в python2.6:

nonprintable = string.maketrans('','').translate(None, string.printable[:-5])
filter = string.maketrans(nonprintable, '.' * len(nonprintable))
1 голос
/ 26 ноября 2009

для реального кода-гольфа, я полагаю, вы бы полностью избежали 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)
...