Вы можете перебирать символы, получать кодовые точки и проверять допустимые значения:
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))