我对这个问题有点过头了,所以请提前赦免我的术语。
我在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
此日志works
此日志breaks
我相信这是打破脚本的编码,因为如果我只是在命令提示符下执行此操作:
type ascii.log > scrubbed.log
然后在scrubbed.log上运行脚本,脚本运行正常(这对我来说实际上很好,因为没有丢失重要信息而且我没有写回文件,只是打印到控制台)。
一个解决方法是在将日志文件传递给Python之前“擦除”日志文件(例如,使用上面的类型管道技巧到一个临时文件,然后运行该脚本),但我想让Python“忽略” “编码,如果可能的话。我也不确定如何检测脚本正在读取什么类型的日志文件,以便我可以采取适当的行动。
我正在阅读this和this,但我的眼睛仍然在他们的头脑中旋转,所以虽然这可能是我的长期策略,但我想知道是否有临时黑客我可以使用
答案 0 :(得分:6)
codecs.open()
将允许您使用特定编码打开文件,它将生成unicode
s。您可以尝试一些,从最可能的可能性到最不可能的(或者该工具可能总是产生UTF-16LE,但是有很多机会)。
答案 1 :(得分:3)
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
中的所有字符都不在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
答案 2 :(得分:0)
Python 2.x期望普通字符串为ASCII(或至少一个字节)。试试这个:
将它放在Python源文件的顶部:
from __future__ import unicode_literals
并将所有str
更改为unicode
。
[编辑]
正如Ignacio Vazquez-Abrams所写,请尝试codecs.open()
打开输入文件。