web-dev-qa-db-ja.com

pythonの文字列から印刷できない文字を取り除く

走るのに使う

$s =~ s/[^[:print:]]//g;

perlで非印刷文字を削除します。

PythonにはPOSIX正規表現クラスはなく、[:print:]と書くことはできません。 Pythonで、文字が印刷可能かどうかを検出する方法はありません。

あなたならどうしますか?

編集:Unicode文字もサポートする必要があります。 string.printableの方法は、出力からそれらを喜んで取り除きます。 curses.ascii.isprintは、Unicode文字に対してfalseを返します。

80
Vinko Vrsalovic

残念ながら、Pythonでは文字列の繰り返しはかなり遅いです。正規表現は、この種のものに対して桁違いに高速です。キャラクタークラスを自分で作成する必要があります。 unicodedataモジュールはこれに非常に役立ちます。特にunicodedata.category() 関数。カテゴリの説明については、 nicode Character Database を参照してください。

import unicodedata, re

all_chars = (unichr(i) for i in xrange(0x110000))
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) == 'Cc')
# or equivalently and much more efficiently
control_chars = ''.join(map(unichr, range(0,32) + range(127,160)))

control_char_re = re.compile('[%s]' % re.escape(control_chars))

def remove_control_chars(s):
    return control_char_re.sub('', s)
74
Ants Aasma

私の知る限り、最もPython /効率的な方法は次のとおりです。

import string

filtered_string = filter(lambda x: x in string.printable, myStr)
65
William Keller

unicodedata.category()関数を使用してフィルターを設定してみてください:

import unicodedata
printable = {'Lu', 'Ll'}
def filter_non_printable(str):
  return ''.join(c for c in str if unicodedata.category(c) in printable)

使用可能なカテゴリについては、 nicodeデータベースの文字プロパティ の175ページの表4-9を参照してください

13
Ber

Python 3、

def filter_nonprintable(text):
    import string
    # Get the difference of all ASCII characters from the set of printable characters
    nonprintable = set([chr(i) for i in range(128)]).difference(string.printable)
    # Use translate to remove all non-printable characters
    return text.translate({ord(character):None for character in nonprintable})

.translate()とregexおよび.replace()の比較方法については、句読点の削除に関するこのStackOverflowの投稿 を参照してください

9
shawnrad

この関数はリスト内包表記とstr.joinを使用するため、O(n ^ 2)ではなく線形時間で実行されます。

from curses.ascii import isprint

def printable(input):
    return ''.join(char for char in input if isprint(char))
5
Kirk Strauser

私が今思いついたのは(上記のpython-izersのおかげです)

def filter_non_printable(str):
  return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])

これは、Unicode文字/文字列で動作する唯一の方法です

より良いオプションはありますか?

2
Vinko Vrsalovic

PythonではPOSIX正規表現クラスはありません

regexライブラリを使用する場合は、次のとおりです。 https://pypi.org/project/regex/

よく管理されており、Unicode正規表現、Posix正規表現などをサポートしています。使用法(メソッドシグネチャ)は、Pythonのreに似たveryです。

ドキュメントから:

[[:alpha:]]; [[:^alpha:]]

POSIX文字クラスがサポートされています。これらは通常、\p{...}の代替形式として扱われます。

(私は所属していません、ただのユーザーです。)

2
Risadinha

以下は、上記よりも高速に実行されます。ご覧ください

''.join([x if x in string.printable else '' for x in Str])
2

「空白」を削除するには、

import re
t = """
\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>&nbsp;</p>\n\t<p>
"""
pat = re.compile(r'[\t\n]')
print(pat.sub("", t))
0
knowingpark

python 3:

re.sub(f'[^{re.escape(string.printable)}]', '', my_string)
0
c6401

以下はUnicode入力で動作し、かなり高速です...

import sys

# build a table mapping all non-printable characters to None
NOPRINT_TRANS_TABLE = {
    i: None for i in range(0, sys.maxunicode + 1) if not chr(i).isprintable()
}

def make_printable(s):
    """Replace non-printable characters in a string."""

    # the translate method on str removes characters
    # that map to None from the string
    return s.translate(NOPRINT_TRANS_TABLE)


assert make_printable('Café') == 'Café'
assert make_printable('\x00\x11Hello') == 'Hello'
assert make_printable('') == ''

私自身のテストでは、このアプローチは、文字列を反復処理してstr.joinを使用して結果を返す関数よりも高速であることが示唆されています。

0
ChrisP