如何从字符串列表中删除所有转义序列?

23

2
最终的字符串对象并不包含任何关于构造它的字符串字面量是否包含转义序列的信息。如果你甚至无法确定是否存在这些转义序列,那么你如何“删除”它们呢? - Sven Marnach
6个回答

42
如果你想要剔除一些不必要的字符,你可以使用 translate 函数来实现:
>>> s="\x01\x02\x10\x13\x20\x21hello world"
>>> print(s)
 !hello world
>>> s
'\x01\x02\x10\x13 !hello world'
>>> escapes = ''.join([chr(char) for char in range(1, 32)])
>>> t = s.translate(None, escapes)
>>> t
' !hello world'

这将删除所有控制字符:
   001   1     01    SOH (start of heading)
   002   2     02    STX (start of text)
   003   3     03    ETX (end of text)
   004   4     04    EOT (end of transmission)
   005   5     05    ENQ (enquiry)
   006   6     06    ACK (acknowledge)
   007   7     07    BEL '\a' (bell)
   010   8     08    BS  '\b' (backspace)
   011   9     09    HT  '\t' (horizontal tab)
   012   10    0A    LF  '\n' (new line)
   013   11    0B    VT  '\v' (vertical tab)
   014   12    0C    FF  '\f' (form feed)
   015   13    0D    CR  '\r' (carriage ret)
   016   14    0E    SO  (shift out)
   017   15    0F    SI  (shift in)
   020   16    10    DLE (data link escape)
   021   17    11    DC1 (device control 1)
   022   18    12    DC2 (device control 2)
   023   19    13    DC3 (device control 3)
   024   20    14    DC4 (device control 4)
   025   21    15    NAK (negative ack.)
   026   22    16    SYN (synchronous idle)
   027   23    17    ETB (end of trans. blk)
   030   24    18    CAN (cancel)
   031   25    19    EM  (end of medium)
   032   26    1A    SUB (substitute)
   033   27    1B    ESC (escape)
   034   28    1C    FS  (file separator)
   035   29    1D    GS  (group separator)
   036   30    1E    RS  (record separator)
   037   31    1F    US  (unit separator)

对于Python 3.1以上版本,顺序是不同的:

>>> s="\x01\x02\x10\x13\x20\x21hello world"
>>> print(s)
 !hello world
>>> s
'\x01\x02\x10\x13 !hello world'
>>> escapes = ''.join([chr(char) for char in range(1, 32)])
>>> translator = str.maketrans('', '', escapes)
>>> t = s.translate(translator)
>>> t
' !hello world'

1
抱歉,那个循环让我感到不安。 escapes = ''.join([chr(char) for char in range(1, 32)]) s.translate(None, escapes) - Rebs
@AdamGriffiths,这是一个不错的变化。谢谢。 - sarnold
我喜欢这个答案,而不是第一个。它运行良好且非常灵活。 - weefwefwqg3
2
这个答案有点过时了。在Python 3.1及以上版本中,您需要在escapes声明后添加这两行代码。translator = str.maketrans('', '', escapes)然后t = s.translate(translator) - Cold Fish
2
@yvihs,感谢您的修复!我已经为新版本的Python编辑了我的答案。 - sarnold

18

类似这样的吗?

>>> from ast import literal_eval
>>> s = r'Hello,\nworld!'
>>> print(literal_eval("'%s'" % s))
Hello,
world!

编辑: 好的,那不是你想要的。像@Sven Marnach 解释的那样,一般情况下无法完成你想要的操作,因为字符串实际上不包含转义序列。这些只是字符串字面值中的符号表示。

你可以使用以下方法从列表中过滤所有包含非ASCII字符的字符串:

def is_ascii(s):
    try:
        s.decode('ascii')
        return True
    except UnicodeDecodeError:
        return False

[s for s in ['william', 'short', '\x80', 'twitter', '\xaa',
             '\xe2', 'video', 'guy', 'ray']
 if is_ascii(s)]

4

您可以使用列表推导式和 str.isalnum() 函数来过滤掉非字母数字的 "单词":

>>> l = ['william', 'short', '\x80', 'twitter', '\xaa', '\xe2', 'video', 'guy', 'ray']
>>> [word for word in l if word.isalnum()]
['william', 'short', 'twitter', 'video', 'guy', 'ray']

如果您希望过滤数字,也可以使用str.isalpha()代替:
>>> l = ['william', 'short', '\x80', 'twitter', '\xaa', '\xe2', 'video', 'guy', 'ray', '456']
>>> [word for word in l if word.isalpha()]
['william', 'short', 'twitter', 'video', 'guy', 'ray']

1
这是许多应用程序的好答案,尽管应注意其他非字母数字字符(如空格)也会受到影响。 - Dr K

3
以下内容适用于我在Python 3.6中的实践:
word = '\t\t\t\t\t\ntest\t msg'
filter = ''.join([chr(i) for i in range(1, 32)])
word.translate(str.maketrans('', '', filter))

输出:

'test msg'

详细说明请参阅此处


1
对我来说工作得非常好! - mcatoen

2

很抱歉,至少在你提出的广泛范围内无法做到。正如其他人所提到的那样,运行时的Python无法区分带有转义序列和不带有转义序列的内容。

例如:

print ('\x61' == 'a')

输出True。所以,除非您尝试对Python脚本进行一些静态分析,否则无法找到这两个字符串之间的差异。


0

在将十六进制转换为字符串时,我遇到了类似的问题。以下是最终在Python中实现的示例:

list_l = ['william', 'short', '\x80', 'twitter', '\xaa', '\xe2', 'video', 'guy', 'ray']
decode_data=[]
for l in list_l:
    data =l.decode('ascii', 'ignore')
    if data != "":
        decode_data.append(data)

# output :[u'william', u'short', u'twitter', u'video', u'guy', u'ray']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接