【问题标题】:How to check each line in a file whether every single character in it is valid utf8?如何检查文件中的每一行是否每个字符都是有效的utf8?
【发布时间】:2020-06-28 08:33:20
【问题描述】:

如何检查文件中每一行中的每个字符是否包含有效的 utf8?应省略包含无效 utf8 字符的行。

这是我的代码不起作用:

lines = [
"correct UTF-8 text: Here come the tests", 
"correct UTF-8 text: You should see the Greek word 'kosme':'κόσμε'", 
"not utf-8: U+FDD0 .. U+FDEF = '﷐﷑﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜﷝﷞﷟﷠﷡﷢﷣﷤﷥﷦﷧﷨﷩﷪﷫﷬﷭﷮﷯'", 
"not utf-8: 6 bytes (U-7FFFFFFF): '������' ",
"ăѣ????ծềſģȟᎥ????ǩľḿꞑȯ????????????????ȶ????????ψ????????????1234567890!$%^&*()-_=+[{]};:',<.>/?~????Ḇ????????٤ḞԍНǏ????ƘԸⲘ????০Ρ????Ɍ????ȚЦ????Ѡ????ƳȤѧᖯć????ễ????????Ⴙ????????????ļṃʼnо????????ᵲꜱ????ừ????ŵ????????ź1234567890!@#$%^&*()-_=+[{]};:,<.>/?~АḂⲤ????????????ꞠꓧȊ????????ꓡ????????Ǭ????????Ŗ????????????????????ꓫŸ????ả????ƀ????ḋếᵮℊ????Ꭵ????кιṃդⱺ????????????????ŧ????ṽẉ????ყž1234567890!@#$%^&*()-_=+[{]};:',<.>/?~Ѧ????ƇᗞΣℱԍҤ١????К????????ƝȎ????????Ṛ????ṮṺƲᏔꓫ????????????Ꮟçძ????????????ḧ????????ҝɭḿ????????????????ṛ????тú????ẃ⤬????????1234567890!@#$%^&*()-_=+[{]};:',<.>/?~????Β????????????????ĢȞỈ????ꓗʟ????ℕ০????????ՀꓢṰǓⅤ????Ⲭ????????????????§"
]

for line in lines:
    try:
        print(line)
    except UnicodeDecodeError:
        print("UnicodeDecodeError: " + line)
        pass

并非所有行都不应打印。我的代码有什么问题?


如果我获取一个文件(我将此页面保存为 file.txt:https://www.w3.org/2001/06/utf-8-test/UTF-8-demo.html)并尝试检查 utf-8,我得到一个 UnicodeDecodeError:

文件“test.py”,第 13 行,用于文件中的行:文件“C:\Users\user\AppData\Local\Programs\Python\Python38\lib\encodings\cp1252.py”,第 23 行, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0] UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 240: character maps to undefined

代码:

file = open("file.txt", "r")

for line in file:
    line = line.strip()
    try:
        print(line)
    except UnicodeDecodeError:
        print("UnicodeDecodeError " + line)
        pass

except-line & pass 是否应该确保如果发生 UnicodeDecodeError,它将被忽略并且脚本继续下一行?

【问题讨论】:

  • "�" is 是一个有效的 UTF-8 字符,否则您无法在问题中显示它。您的文件包含哪些确切的 字节...?
  • print("not utf-8: 6 bytes (U-7FFFFFFF): '������' ")
  • 我从这个问题中获取了文件:stackoverflow.com/questions/1301402/example-invalid-utf8-string(Markus Kuhn 的 UTF-8 解码器能力和压力测试文件)。此文件中的所有行也会被打印出来。
  • 您是否将该文件的内容复制并粘贴到您自己的文件中?那你还没有用它复制那些问题。您需要按原样使用该文件,或者生成一个包含那些有问题的字节序列的实际文件,其级别比使用常规文本编辑器所能做的低。
  • 老兄,您需要将格式错误的 UTF-8 代码单元序列存储为bytes。那就试试.decode("utf-8")吧。 lines 列表中的所有字符串实际上都是有效的 UTF-8 字符串。

标签: python python-3.x


【解决方案1】:

问题是您复制并粘贴了 显示的 文本。由于我对屏幕从来没有信心,我用[(i,hex(ord(i))) for i in t] 控制了最后两个字符串的实际内容。

第四个给出:

[('n', '0x6e'), ('o', '0x6f'), ('t', '0x74'), (' ', '0x20'), ('u', '0x75'), ('t', '0x74'), ('f', '0x66'), ('-', '0x2d'), ('8', '0x38'), (':', '0x3a'), (' ', '0x20'), ('6', '0x36'), (' ', '0x20'), ('b', '0x62'), ('y', '0x79'), ('t', '0x74'), ('e', '0x65'), ('s', '0x73'), (' ', '0x20'), ('(', '0x28'), ('U', '0x55'), ('-', '0x2d'), ('7', '0x37'), ('F', '0x46'), ('F', '0x46'), ('F', '0x46'), ('F', '0x46'), ('F', '0x46'), ('F', '0x46'), ('F', '0x46'), (')', '0x29'), (':', '0x3a'), (' ', '0x20'), ("'", '0x27'), ('�', '0xfffd'), ('�', '0xfffd'), ('�', '0xfffd'), ('�', '0xfffd'), ('�', '0xfffd'), ('�', '0xfffd'), ("'", '0x27'), (' ', '0x20')]

所有违规字节已被替换字符 U+FFFD 替换,这是一个完全有效的 Unicode 字符。所以这是一个正确的字符串

第三个给出:

[('n', '0x6e'), ('o', '0x6f'), ('t', '0x74'), (' ', '0x20'), ('u', '0x75'), ('t', '0x74'), ('f', '0x66'), ('-', '0x2d'), ('8', '0x38'), (':', '0x3a'), (' ', '0x20'), ('U', '0x55'), ('+', '0x2b'), ('F', '0x46'), ('D', '0x44'), ('D', '0x44'), ('0', '0x30'), (' ', '0x20'), ('.', '0x2e'), ('.', '0x2e'), (' ', '0x20'), ('U', '0x55'), ('+', '0x2b'), ('F', '0x46'), ('D', '0x44'), ('E', '0x45'), ('F', '0x46'), (' ', '0x20'), ('=', '0x3d'), (' ', '0x20'), ("'", '0x27'), ('\ufdd0', '0xfdd0'), ('\ufdd1', '0xfdd1'), ('\ufdd2', '0xfdd2'), ('\ufdd3', '0xfdd3'), ('\ufdd4', '0xfdd4'), ('\ufdd5', '0xfdd5'), ('\ufdd6', '0xfdd6'), ('\ufdd7', '0xfdd7'), ('\ufdd8', '0xfdd8'), ('\ufdd9', '0xfdd9'), ('\ufdda', '0xfdda'), ('\ufddb', '0xfddb'), ('\ufddc', '0xfddc'), ('\ufddd', '0xfddd'), ('\ufdde', '0xfdde'), ('\ufddf', '0xfddf'), ('\ufde0', '0xfde0'), ('\ufde1', '0xfde1'), ('\ufde2', '0xfde2'), ('\ufde3', '0xfde3'), ('\ufde4', '0xfde4'), ('\ufde5', '0xfde5'), ('\ufde6', '0xfde6'), ('\ufde7', '0xfde7'), ('\ufde8', '0xfde8'), ('\ufde9', '0xfde9'), ('\ufdea', '0xfdea'), ('\ufdeb', '0xfdeb'), ('\ufdec', '0xfdec'), ('\ufded', '0xfded'), ('\ufdee', '0xfdee'), ('\ufdef', '0xfdef'), ("'", '0x27')]

这是一个更好的测试:U+FDDD0 和 U+FDEF 之间的字符确实不是有效的 Unicode 字符。这里发生的情况是 Python 只是不关心并愉快地处理它们。

如果你想控制它们是真正有效的 Unicode 字符,你可以使用unicodedata 模块。它的name 函数将给出所有已知有效字符的正式名称,并对那些不是的人提出值错误:

>>> unicodedata.name('�')

'REPLACEMENT CHARACTER'
>>> unicodedata.name('\uFFFD')

'REPLACEMENT CHARACTER'
>>> unicodedata.name('\uFDD0')

Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    unicodedata.name('\uFDD0')
ValueError: no such name

但是如果你想测试 bytes 是否代表有效的 utf-8,那么你应该使用 bytes 而不是 unicode 字符串。

【讨论】:

    【解决方案2】:

    由于示例中的行是 str 文字,它们是有效的 unicode 序列。

    请尝试用这样的原始字节替换行:

    lines = [
        b"valid utf-8",
        b"not utf-8: U+FDD0 .. U+FDEF = '\xFD\xD0\FD\EF",
    ]
    
    for line in lines:
        try:
            print(line.decode())
        except UnicodeDecodeError:
            print('Invalid UTF-8: {}'.format(line))
    

    注意循环中的显式 decode 调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      相关资源
      最近更新 更多