在python中从字符串中剥离不可打印的字符

在python中从字符串中剥离不可打印的字符,python,string,non-printable,Python,String,Non Printable,我过去经常跑步 $s =~ s/[^[:print:]]//g; 在Perl上删除不可打印的字符 Python中没有POSIX正则表达式类,我无法编写[:print:]让它代表我想要的内容。我知道Python中没有办法检测字符是否可打印 你会怎么做 编辑:它还必须支持Unicode字符。string.printable方法将很高兴地将它们从输出中删除。 curses.ascii.isprint对于任何unicode字符都将返回false。我现在想到的最好的方法是(感谢上面的python ize

我过去经常跑步

$s =~ s/[^[:print:]]//g;
在Perl上删除不可打印的字符

Python中没有POSIX正则表达式类,我无法编写[:print:]让它代表我想要的内容。我知道Python中没有办法检测字符是否可打印

你会怎么做

编辑:它还必须支持Unicode字符。string.printable方法将很高兴地将它们从输出中删除。
curses.ascii.isprint对于任何unicode字符都将返回false。

我现在想到的最好的方法是(感谢上面的python izers)

这是我发现的唯一适用于Unicode字符/字符串的方法


有更好的选择吗?

据我所知,最具吸引力/效率的方法是:

import string

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

此函数使用列表理解和str.join,因此它以线性时间而不是O(n^2)运行:


不幸的是,在Python中对字符串进行迭代相当慢。对于这类事情,正则表达式要快一个数量级以上。你只需要自己构建角色类。unicodedata模块对此非常有用,尤其是unicodedata.category()函数。有关类别的说明,请参见

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)
用于蟒蛇2

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
    (对照组):65
  • Cf
    (格式):161
  • Cs
    (代理):2048
  • Co
    (私人使用):137468
  • Cn
    (未分配):836601

编辑从评论中添加建议。

您可以尝试使用
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)
有关Python 3中可用的类别,请参见中第175页的表4-9

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})
有关.translate()与regex和.replace()的比较,请参见


如果unicodedata.category(c)='Cc')使用@Ants Aasma.所示的删除“空白”,则可以通过以下方式生成范围:
不可打印=(ord(c)表示范围中的c(chr(i)表示范围中的i(sys.maxunicode))

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))
重新导入
t=”“”
\n\t

\n\t\n\t

\n\t

\n\t """ pat=re.compile(r'[\t\n]') 印刷品(附页(“,t))
下面的一个执行速度比上面其他的快。看一看

''.join([x if x in string.printable else '' for x in Str])
Python中没有POSIX正则表达式类

在使用
regex
库时,存在以下问题:

它维护得很好,支持Unicode正则表达式、Posix正则表达式和更多。用法(方法签名)非常类似于Python的
re

从文件中:

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

支持POSIX字符类 通常被视为
\p{…}
的替代形式


(我不是附属机构,只是一个用户。)

python 3中的另一个选项:

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

以下内容适用于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

返回结果的函数更快,这些函数根据和的答案改编:


根据@Ber的回答,我建议只删除以下定义的控制字符:

导入Unicode数据
def过滤器不可打印:
返回“”。join(如果不是Unicode数据,则c代表s中的c.category(c).startswith('c'))


您可能需要筛选的\u string=''.join(筛选(lambda x:x in string.printable,myStr)这样您就可以得到一个字符串。遗憾的是,string.printable不包含unicode字符,因此输出中不会出现ü或ó…可能还有其他内容?您应该使用列表理解或生成器表达式,而不是filter+lambda。其中一个将在99.9%的时间内更快。“”加入(如果s在string.printable中,则s代表myStr中的s)@AaronGallagher:99.9%的速度?你是从哪里得到这个数字的?性能比较远没有那么差。嗨,William。这种方法似乎删除了所有非ASCII字符。Unicode中有许多可打印的非ASCII字符!这里的“Cc”够了吗?我不知道,我只是在问——在我看来,其他一些“C”分类es也可能是此筛选器的候选项。此函数在发布时删除了一半希伯来文字符。对于给定的两种方法,我都得到了相同的效果。从性能角度来看,string.translate()在这种情况下不是工作得更快吗?请参阅Use
all_chars=(unichr(I)表示xrange(sys.maxunicode)中的I)
以避免狭隘的构建错误。对于我来说,
control\u chars=='\x00-\x1f\x7f-\x9f'
(在Python 3.5.2上测试)除非您使用的是Python 2.3,否则内部[]是冗余的。“return.”join(c代表c…)并不是很冗余。它们有不同的含义(和性能特征),尽管最终结果是一样的。范围的另一端是否也应该受到保护?:“ord(c)但也有Unicode字符无法打印。您开始的列表理解并没有在最后一行结束。我建议您完全删除开头的括号。谢谢您指出这一点。我据此编辑了文章。这似乎是最直接、最直接的方法。谢谢。@csaboth这三种方法都是有效的,并产生了t同一个集合。您的可能是指定集合文字的最好方法。@AnubhavJhalani您可以向筛选器添加更多Unicode类别。若要在字母之外保留空格和数字,请使用
printable={Lu',Ll',Zs',Nd'}
”。加入([c如果0x21这对我和它的1行非常有效。谢谢出于某种原因,这在windows上非常有效,但在linux上无法使用,我不得不将f改为r,但我不确定这是解决方案。听起来你的linux Python太旧了,不支持f字符串。r字符串完全不同,
re.sub(f'[^{re.escape(string.printable)}]', '', my_string)
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('') == ''
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)