如何检测 python 中的未解码字符?
How to detect undecoded characters in python?
我从 csv 文件中获取数据,对其进行处理,然后将其写入文本模板。
遇到无法编码的字符时出现问题。
例如,当我遇到一个用中文写的值时,当我用某种 csv 编辑器(例如 Linux 的 LibreOffice Calc)打开它时,所选字段是空白的。
但是当我在我的脚本中通过 csv.reader 获取数据时,我可以看到它实际上是一个没有被正确解码的字符串。
当我尝试将它写入模板时,我得到了这个奇怪的 SUB 字符串。
这里是问题的分解:
for row in csv.DictReader(csvfile):
# take value from the row and store it in a dictionary
....
# take the values from the dictionary and write them to a template
with open('template.txt', 'r+') as template:
src = Template(template.read())
content = src.substitute(rec)
with open('myoutput.txt', 'w') as bill:
bill.write(content)
template.txt 看起来像这样:
$name
$address
$city
...
所有这些都会生成这样的 txt 文件:
Bill
North Grove 14
Scottsdale
...
如果任何字典值是空的,例如空字符串 ''
,我的模板渲染函数会忽略该标记,例如,如果特定行中缺少 address
属性,则输出将是
Bill
Scottsdale
...
当我尝试用我的中文数据这样做时,我的函数确实写入了数据,因为有问题的字符串不为空。当我将它们写入模板时,最终结果如下所示:
SUB
SUB
Hong Kong
...
如何正确显示我的数据?还有一种方法可以跳过该数据,例如可以尝试解码数据的方法,如果不成功,则将其转换为空字符串。
P.S。 try except
在这里不起作用,因为 mystring.encode('utf-8')
或 mystring.encode('latin-1')
会对字符串进行编码,但它仍然会作为垃圾输出。
编辑
打印出问题行后,问题值的输出如下:
{'Name': '\x1a \x1a\x1a', 'State': '\x1a\x1a\x1a'}
\x1a
就是ASCII substitute character。这就是您在输出中看到 "SUB" 的原因。此字符通常用作尝试解码字节但失败的程序的替换。
您的 CSV 文件不包含有效数据。可能它是从包含有效数据的源开始生成的,但文件本身不再包含有效数据。
只是猜测:也许,您是用 LibreOffice 打开文件然后保存的吗?
如果您想检查您的字符串是否包含不可打印的 ASCII 字符,请使用:
def is_printable(data):
return all(c in string.printable for c in data)
如果要删除不可打印的 ASCII 字符:
def strip_unprintable(data):
return ''.join(c for c in data if c in string.printable)
如果要处理 Unicode 字符串,则将 c in string.printable
替换为:
ord(c) > 0x1f and ord(c) != 0x7f and not (0x80 <= ord(c) <= 0x9f)
(归功于 What is the range of Unicode Printable Characters?)
感谢@Andrea Corbellini,您的回答帮助我找到了解决方案。
def stringcheck(line):
for letter in line:
if letter not in string.printable:
return 0
return 1
但是我认为这不是最符合 Python 风格的方法,因此我们将不胜感激任何关于如何改进它的建议。
我从 csv 文件中获取数据,对其进行处理,然后将其写入文本模板。
遇到无法编码的字符时出现问题。
例如,当我遇到一个用中文写的值时,当我用某种 csv 编辑器(例如 Linux 的 LibreOffice Calc)打开它时,所选字段是空白的。
但是当我在我的脚本中通过 csv.reader 获取数据时,我可以看到它实际上是一个没有被正确解码的字符串。 当我尝试将它写入模板时,我得到了这个奇怪的 SUB 字符串。
这里是问题的分解:
for row in csv.DictReader(csvfile):
# take value from the row and store it in a dictionary
....
# take the values from the dictionary and write them to a template
with open('template.txt', 'r+') as template:
src = Template(template.read())
content = src.substitute(rec)
with open('myoutput.txt', 'w') as bill:
bill.write(content)
template.txt 看起来像这样:
$name
$address
$city
...
所有这些都会生成这样的 txt 文件:
Bill
North Grove 14
Scottsdale
...
如果任何字典值是空的,例如空字符串 ''
,我的模板渲染函数会忽略该标记,例如,如果特定行中缺少 address
属性,则输出将是
Bill
Scottsdale
...
当我尝试用我的中文数据这样做时,我的函数确实写入了数据,因为有问题的字符串不为空。当我将它们写入模板时,最终结果如下所示:
SUB
SUB
Hong Kong
...
如何正确显示我的数据?还有一种方法可以跳过该数据,例如可以尝试解码数据的方法,如果不成功,则将其转换为空字符串。
P.S。 try except
在这里不起作用,因为 mystring.encode('utf-8')
或 mystring.encode('latin-1')
会对字符串进行编码,但它仍然会作为垃圾输出。
编辑
打印出问题行后,问题值的输出如下:
{'Name': '\x1a \x1a\x1a', 'State': '\x1a\x1a\x1a'}
\x1a
就是ASCII substitute character。这就是您在输出中看到 "SUB" 的原因。此字符通常用作尝试解码字节但失败的程序的替换。
您的 CSV 文件不包含有效数据。可能它是从包含有效数据的源开始生成的,但文件本身不再包含有效数据。
只是猜测:也许,您是用 LibreOffice 打开文件然后保存的吗?
如果您想检查您的字符串是否包含不可打印的 ASCII 字符,请使用:
def is_printable(data):
return all(c in string.printable for c in data)
如果要删除不可打印的 ASCII 字符:
def strip_unprintable(data):
return ''.join(c for c in data if c in string.printable)
如果要处理 Unicode 字符串,则将 c in string.printable
替换为:
ord(c) > 0x1f and ord(c) != 0x7f and not (0x80 <= ord(c) <= 0x9f)
(归功于 What is the range of Unicode Printable Characters?)
感谢@Andrea Corbellini,您的回答帮助我找到了解决方案。
def stringcheck(line):
for letter in line:
if letter not in string.printable:
return 0
return 1
但是我认为这不是最符合 Python 风格的方法,因此我们将不胜感激任何关于如何改进它的建议。