我过去跑步
$s =~ s/[^[:print:]]//g;
在Perl上摆脱不可打印的字符。
在Python中,没有POSIX正则表达式类,并且我不能写[:print:]来表示我想要的意思。我不知道在Python中无法检测字符是否可打印。
你会怎么做?
编辑:它也必须支持Unicode字符。string.printable方式会很乐意将它们从输出中剥离。curses.ascii.isprint将为任何unicode字符返回false。
我过去跑步
$s =~ s/[^[:print:]]//g;
在Perl上摆脱不可打印的字符。
在Python中,没有POSIX正则表达式类,并且我不能写[:print:]来表示我想要的意思。我不知道在Python中无法检测字符是否可打印。
你会怎么做?
编辑:它也必须支持Unicode字符。string.printable方式会很乐意将它们从输出中剥离。curses.ascii.isprint将为任何unicode字符返回false。
Answers:
不幸的是,在Python中遍历字符串相当慢。对于这种事情,正则表达式的速度要快一个数量级。您只需要自己构建角色类即可。该unicodedata模块是这个相当有帮助,尤其是unicodedata.category()函数。有关类别的说明,请参见Unicode字符数据库。
import unicodedata, re, itertools, sys
all_chars = (chr(i) for i in range(sys.maxunicode))
categories = {'Cc'}
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) in categories)
# or equivalently and much more efficiently
control_chars = ''.join(map(chr, itertools.chain(range(0x00,0x20), range(0x7f,0xa0))))
control_char_re = re.compile('[%s]' % re.escape(control_chars))
def remove_control_chars(s):
return control_char_re.sub('', s)
对于Python2
import unicodedata, re, sys
all_chars = (unichr(i) for i in xrange(sys.maxunicode))
categories = {'Cc'}
control_chars = ''.join(c for c in all_chars if unicodedata.category(c) in categories)
# or equivalently and much more efficiently
control_chars = ''.join(map(unichr, range(0x00,0x20) + range(0x7f,0xa0)))
control_char_re = re.compile('[%s]' % re.escape(control_chars))
def remove_control_chars(s):
return control_char_re.sub('', s)
对于某些用例,最好使用其他类别(例如,来自控制组的所有类别),尽管这可能会减慢处理时间并显着增加内存使用。每个类别的字符数:
Cc
(控制):65Cf
(格式):161Cs
(代理):2048Co
(私人使用):137468Cn
(未分配):836601编辑从注释中添加建议。
all_chars = (unichr(i) for i in xrange(sys.maxunicode))
来避免狭隘生成错误。
control_chars == '\x00-\x1f\x7f-\x9f'
(已在Python 3.5.2上测试)
据我所知,最pythonic /最有效的方法是:
import string
filtered_string = filter(lambda x: x in string.printable, myStr)
您可以尝试使用以下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)
有关可用类别,请参见Unicode数据库字符属性中的表4-9(第175页)。
printable = {'Lu', 'Ll', Zs', 'Nd'}
在Python 3中,
def filter_nonprintable(text):
import itertools
# Use characters of control category
nonprintable = itertools.chain(range(0x00,0x20),range(0x7f,0xa0))
# Use translate to remove all non-printable characters
return text.translate({character:None for character in nonprintable})
请参阅有关删除标点符号的StackOverflow帖子,了解.translate()与regex和.replace()的比较方式
可以通过nonprintable = (ord(c) for c in (chr(i) for i in range(sys.maxunicode)) if unicodedata.category(c)=='Cc')
使用@Ants Aasma所示的Unicode字符数据库类别来生成范围。
text.translate({c:None for c in itertools.chain(range(0x00,0x20),range(0x7f,0xa0))})
。
以下将适用于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
。
LINE_BREAK_CHARACTERS = set(["\n", "\r"])
和and not chr(i) in LINE_BREAK_CHARACTERS
。
python 3中的另一个选项:
re.sub(f'[^{re.escape(string.printable)}]', '', my_string)
r'[^' + re.escape(string.printable) + r']'
。(我不认为这re.escape()
是完全正确的,但是如果
我现在想出的最好的是(由于上面的python-izers)
def filter_non_printable(str):
return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])
这是我发现可用于Unicode字符/字符串的唯一方法
还有更好的选择吗?
下面的一个比上面的其他要快。看一看
''.join([x if x in string.printable else '' for x in Str])
"".join([c if 0x21<=ord(c) and ord(c)<=0x7e else "" for c in ss])
在Python中,没有POSIX正则表达式类
使用regex
库时有: https //pypi.org/project/regex/
它维护良好,并支持Unicode regex,Posix regex等。用法(方法签名)非常与Python的相似re
。
从文档中:
[[:alpha:]]; [[:^alpha:]]
支持POSIX字符类。这些通常被视为
\p{...}
。
(我没有隶属关系,只是一个用户。)
根据@Ber的答案,我建议仅删除Unicode字符数据库类别中定义的控制字符:
import unicodedata
def filter_non_printable(s):
return ''.join(c for c in s if not unicodedata.category(c).startswith('C'))
改编自Ants Aasma和shawnrad的答案:
nonprintable = set(map(chr, list(range(0,32)) + list(range(127,160))))
ord_dict = {ord(character):None for character in nonprintable}
def filter_nonprintable(text):
return text.translate(ord_dict)
#use
str = "this is my string"
str = filter_nonprintable(str)
print(str)
在Python 3.7.7上测试