【问题标题】:How can I sanitize a string so that it only contains only printable ASCII chars?如何清理字符串以使其仅包含可打印的 ASCII 字符?
【发布时间】:2019-11-11 04:36:09
【问题描述】:

我想要一个可以清理字符串的函数。清理程序返回的字符串应该只包含 ASCII 字符 #32(空格字符)到 ASCII #126('~')。

ASCII 字符#9(制表符)将替换为四个空格。所有其他非法字符都将替换为空字符串。例如,“\n”将被替换为空字符串。我们不希望非法字符被表示相关转义序列的字符串替换。例如,我们确实希望将换行符替换为反斜杠字符和“n”字符。

如果最终的字符串是 Unicode 编码的,而不是 ASCII 编码,那就没问题了。我只希望唯一允许的字符如下:

" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

示例用法:

unsafe_string = "\u2502\u251cAPPLES\n\t\t\t\t\t\r\r AND \n\nBANANAS"
safe_string = sanitize(unsafe_string)
print(safe_string)

输出:

APPLES                     AND BANANAS   

编辑:

以下尝试的解决方案不起作用,因为它们无法过滤掉换行符。

import string
import re

unsafe_string = "\u2502\u251cAPPLES\n\t\t\t\t\t\r\r AND \n\nBANANAS"

safe_string = re.sub(r'[^\x00-\x7f]',r'', unsafe_string) 
print(safe_string)    

printable = set(string.printable)
safe_string = ''.join(filter(lambda x: x in printable, unsafe_string))
print(safe_string)

【问题讨论】:

标签: python string io ascii


【解决方案1】:

您可以遍历字符、获取代码点并检查允许的值:

def sanitize(unsafe_str): 
    allowed_range = set(range(32, 127)) 
    safe_str = '' 
    for char in unsafe_str: 
        cp = ord(char) 
        if cp in allowed_range: 
            safe_str += char 
        elif cp == 9: 
            safe_str += ' ' * 4 
    return re.sub(r'\s+', ' ', safe_str) 

示例:

In [1042]: unsafe_string = "\u2502\u251cAPPLES\n\t\t\t\t\t\r\r AND \n\nBANANAS"                                                                                                                             

In [1043]: def sanitize(unsafe_str): 
      ...:     allowed_range = set(range(32, 127)) 
      ...:     safe_str = '' 
      ...:     for char in unsafe_str: 
      ...:         cp = ord(char) 
      ...:         if cp in allowed_range: 
      ...:             safe_str += char 
      ...:         elif cp == 9: 
      ...:             safe_str += ' ' * 4 
      ...:     return re.sub(r'\s+', ' ', safe_str) 
      ...:      
      ...:                                                                                                                                                                                                  

In [1044]: sanitize(unsafe_string)                                                                                                                                                                          
Out[1044]: 'APPLES AND BANANAS'

最后一个re.sub(r'\s+', ' ', safe_str) 块是将空格压缩为一个。如果您不希望这样做,只需 return safe_str:

In [1046]: def sanitize(unsafe_str): 
      ...:     allowed_range = set(range(32, 127)) 
      ...:     safe_str = '' 
      ...:     for char in unsafe_str: 
      ...:         cp = ord(char) 
      ...:         if cp in allowed_range: 
      ...:             safe_str += char 
      ...:         elif cp == 9: 
      ...:             safe_str += ' ' * 4 
      ...:     return safe_str 
      ...:                                                                                                                                                                                                     

In [1047]: sanitize(unsafe_string)                                                                                                                                                                          
Out[1047]: 'APPLES                     AND BANANAS'

FWIW,这会在函数的每次运行时生成允许列表,但由于它是一个常量,您可以将它放在模块级别使其只生成一次,例如:

ALLOWED_RANGE = set(range(32, 127)) 

【讨论】:

  • 用 4 个空格替换制表符然后将它们折叠成一个是没有意义的,所以我怀疑 OP 想要这样。
【解决方案2】:
import re

def sanitize(s):
    s = s.replace("\t", "    ")
    return re.sub(r"[^ -~]", "", s)

[ -~] 表示“从(空格)到~ 范围内的所有内容”。在开头添加^ 意味着除此之外的一切。

输出是:

APPLES                     AND BANANAS

在您的示例输出中,您忘记用空格替换制表符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2020-11-17
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多