解析格式化文本文件的 Pythonic 方式
Pythonic way to parse a formatted text file
以我的方式学习python 我想以这种方式解析格式化的文本文件的正确方法:
game (
name "Chess (1981)(M.C. Rakaska, S.W. Huggins) [Strategy, Chess].zip"
file ( name Chess.bas size 19129 date 2007/01/31 19:46:20 crc 50577473 )
file ( name Chess.exe size 46464 date 1998/12/25 19:46:00 crc 826d1c0d )
file ( name file_id.diz size 198 date 2014/11/23 07:53:32 crc 72399680 )
)
有多个这样的条目。
AFAIK 阅读这里后有很多方法可以做到这一点。我可以手动解析它(剥离、查找数据等),我可以使用某种正则表达式来解析行,即使我找到了一个模块 PyParse(对我来说有点复杂)。
我确信有一种更 pythonic 的方法可以手动完成,也许使用 PyParse?手工完成似乎是一种快速破解...
这些文件包含在 zip 文件中,很多都在 50MB 左右,但我已经解决了将文本文件加载到内存中并剥离 header.
有什么正确方法的提示吗?
基本上取决于数据的不规则性。
我在这里可以看到两个并发症;
游戏名称用双引号括起来。但是,如果名称还 包含 双引号怎么办?
如果文件名包含空格怎么办?
看起来这两个问题都可以使用内置 re
模块的常规表达式来充分解决。所以请记住 Zen of Python 在这种情况下,没有必要让它变得更复杂并使用完整的解析器。
最后,在阅读了这里和那里以及许多测试之后,我得出了这个结论。
这是更大循环的摘录,我在其中解析文件中的其他类型的数据。
来自其他语言(c++、Pascal、PHP)对我来说有点奇怪 python 3.x 处理字符串的方式。我发现从 ZIP 文件内部读取我得到二进制格式的字符串(作为字节),所以我必须在很多网站等中使用 "b"。但也许这是另一个问题的 material。
无论如何,这对我有用。
gdregex = re.compile(r"file\s*\(\s*name\s+(.+)\s+size\s+(\d+)\s+date\s+(.+)\s+crc\s+([0-9a-fA-F]{8})\s*\)", re.IGNORECASE | re.VERBOSE | re.MULTILINE)
with zipfile.ZipFile(dat_file) as datz:
with datz.open('filetoprocess.txt') as datf:
for line in datf:
line=line.strip().lower()
if line.startswith(b"game ("):
# New entry
is_new_entry = True
entry = []
continue
if is_new_entry:
if line.startswith(b"name"):
gamename = str(line[len("name")+2:])
if line.startswith(b"file"):
line = str(line)
gamedatarx = gdregex.split(line,0)
entry = []
entry.append(gamename)
entry.extend(gamedatarx[1:4])
print(entry)
if line==b')' and is_new_entry:
is_new_entry = False
以我的方式学习python 我想以这种方式解析格式化的文本文件的正确方法:
game (
name "Chess (1981)(M.C. Rakaska, S.W. Huggins) [Strategy, Chess].zip"
file ( name Chess.bas size 19129 date 2007/01/31 19:46:20 crc 50577473 )
file ( name Chess.exe size 46464 date 1998/12/25 19:46:00 crc 826d1c0d )
file ( name file_id.diz size 198 date 2014/11/23 07:53:32 crc 72399680 )
)
有多个这样的条目。
AFAIK 阅读这里后有很多方法可以做到这一点。我可以手动解析它(剥离、查找数据等),我可以使用某种正则表达式来解析行,即使我找到了一个模块 PyParse(对我来说有点复杂)。
我确信有一种更 pythonic 的方法可以手动完成,也许使用 PyParse?手工完成似乎是一种快速破解...
这些文件包含在 zip 文件中,很多都在 50MB 左右,但我已经解决了将文本文件加载到内存中并剥离 header.
有什么正确方法的提示吗?
基本上取决于数据的不规则性。 我在这里可以看到两个并发症;
游戏名称用双引号括起来。但是,如果名称还 包含 双引号怎么办?
如果文件名包含空格怎么办?
看起来这两个问题都可以使用内置 re
模块的常规表达式来充分解决。所以请记住 Zen of Python 在这种情况下,没有必要让它变得更复杂并使用完整的解析器。
最后,在阅读了这里和那里以及许多测试之后,我得出了这个结论。
这是更大循环的摘录,我在其中解析文件中的其他类型的数据。 来自其他语言(c++、Pascal、PHP)对我来说有点奇怪 python 3.x 处理字符串的方式。我发现从 ZIP 文件内部读取我得到二进制格式的字符串(作为字节),所以我必须在很多网站等中使用 "b"。但也许这是另一个问题的 material。
无论如何,这对我有用。
gdregex = re.compile(r"file\s*\(\s*name\s+(.+)\s+size\s+(\d+)\s+date\s+(.+)\s+crc\s+([0-9a-fA-F]{8})\s*\)", re.IGNORECASE | re.VERBOSE | re.MULTILINE)
with zipfile.ZipFile(dat_file) as datz:
with datz.open('filetoprocess.txt') as datf:
for line in datf:
line=line.strip().lower()
if line.startswith(b"game ("):
# New entry
is_new_entry = True
entry = []
continue
if is_new_entry:
if line.startswith(b"name"):
gamename = str(line[len("name")+2:])
if line.startswith(b"file"):
line = str(line)
gamedatarx = gdregex.split(line,0)
entry = []
entry.append(gamename)
entry.extend(gamedatarx[1:4])
print(entry)
if line==b')' and is_new_entry:
is_new_entry = False