繁体   English   中英

Python kludge将UCS-2(UTF-16?)读取为ASCII

[英]Python kludge to read UCS-2 (UTF-16?) as ASCII

我对这个问题有点过头了,所以请提前原谅我的术语。

我在Windows XP上使用Python 2.7运行它。

我发现一些Python代码读取日志文件,做一些事情,然后显示一些东西。

什么,这还不够详细? 好的,这是一个简化版本:

#!/usr/bin/python

import re
import sys

class NotSupportedTOCError(Exception):
    pass

def filter_toc_entries(lines):
    while True:
        line = lines.next()
        if re.match(r""" \s* 
                   .+\s+ \| (?#track)
                \s+.+\s+ \| (?#start)
                \s+.+\s+ \| (?#length)
                \s+.+\s+ \| (?#start sec)
                \s+.+\s*$   (?#end sec)
                """, line, re.X):
            lines.next()
            break

    while True:
        line = lines.next()
        m = re.match(r"""
            ^\s*
            (?P<num>\d+)
            \s*\|\s*
            (?P<start_time>[0-9:.]+)
            \s*\|\s*
            (?P<length_time>[0-9:.]+)
            \s*\|\s*
            (?P<start_sector>\d+)
            \s*\|\s*
            (?P<end_sector>\d+)
            \s*$
            """, line, re.X)
        if not m:
            break
        yield m.groupdict()

def calculate_mb_toc_numbers(eac_entries):
    eac = list(eac_entries)
    num_tracks = len(eac)

    tracknums = [int(e['num']) for e in eac]
    if range(1,num_tracks+1) != tracknums:
        raise NotSupportedTOCError("Non-standard track number sequence: %s", tracknums)

    leadout_offset = int(eac[-1]['end_sector']) + 150 + 1
    offsets = [(int(x['start_sector']) + 150) for x in eac]
    return [1, num_tracks, leadout_offset] + offsets

f = open(sys.argv[1])

mb_toc_urlpart = "%20".join(str(x) for x in calculate_mb_toc_numbers(filter_toc_entries(f)))

print mb_toc_urlpart

只要日志文件是“简单”文本,代码就可以正常工作(我很想说ASCII虽然可能不精确/准确 - 例如Notepad ++表示它是ANSI)。

但是,该脚本不适用于某些日志文件(在这些情况下,Notepad ++说“UCS-2 Little Endian”)。

我收到以下错误:

Traceback (most recent call last):
  File "simple.py", line 55, in <module>
    mb_toc_urlpart = "%20".join(str(x) for x in calculate_mb_toc_numbers(filter_
toc_entries(f)))
  File "simple.py", line 49, in calculate_mb_toc_numbers
    leadout_offset = int(eac[-1]['end_sector']) + 150 + 1
IndexError: list index out of range

这个日志有效

此日志中断

我相信这是打破脚本的编码,因为如果我只是在命令提示符下执行此操作:

type ascii.log > scrubbed.log

然后在scrubbed.log上运行脚本,脚本工作正常(这对我的目的来说很好,因为没有丢失重要信息,我没有写回文件,只是打印到控制台)。

一种解决方法是在将日志文件传递给Python之前“擦除”日志文件(例如,使用上面的类型管道技巧到临时文件,然后运行脚本),但我想让Python“忽略”编码如果它是可能的。 我也不确定如何检测脚本正在读取什么类型的日志文件,以便我可以采取适当的行动。

我正在读这个这个,但我的眼睛仍在他们的头脑中旋转,所以虽然这可能是我的长期战略,但我想知道是否有一个我可以使用的临时黑客。

codecs.open()允许您使用特定的编码打开文件,它将生成unicode 您可以尝试一些,从最可能的可能性到最不可能的(或者该工具可能总是产生UTF-16LE,但是有很多机会)。

此外, “Python中的Unicode,完全揭秘”

works.log似乎以ASCII编码:

>>> data = open('works.log', 'rb').read()
>>> all(d < '\x80' for d in data)
True

breaks.log似乎以UTF-16LE编码 - 它以2个字节'\\xff\\xfe' breaks.log中的所有字符breaks.log在ASCII范围内:

>>> data = open('breaks.log', 'rb').read()
>>> data[:2]
'\xff\xfe'
>>> udata = data.decode('utf16')
>>> all(d < u'\x80' for d in udata)
True

如果这是唯一的两种可能性,那么你应该能够逃脱以下攻击。 更改主线代码:

f = open(sys.argv[1])
mb_toc_urlpart = "%20".join(
    str(x) for x in calculate_mb_toc_numbers(filter_toc_entries(f)))
print mb_toc_urlpart

对此:

f = open(sys.argv[1], 'rb')
data = f.read()
f.close()
if data[:2] == '\xff\xfe':
    data = data.decode('utf16').encode('ascii')
# ilines is a generator which produces newline-terminated strings
ilines = (line + '\n' for line in data.splitlines())
mb_toc_urlpart = "%20".join(
    str(x) for x in calculate_mb_toc_numbers(filter_toc_entries(ilines))        )
print mb_toc_urlpart

Python 2.x期望普通字符串是ASCII(或至少一个字节)。 尝试这个:

把它放在Python源文件的顶部:

from __future__ import unicode_literals

并将所有str更改为unicode

[编辑]

正如Ignacio Vazquez-Abrams所写,尝试使用codecs.open()来打开输入文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM