繁体   English   中英

从二进制文件中提取文本(在Windows 7上使用Python 2.7)

[英]Extract Text from a Binary File (using Python 2.7 on Windows 7)

我有一个大约5MB的二进制文件..其中有很多散布的文本..和控制字符..

这实际上等效于SITATEX Application(来自SITA)的Outlook .pst文件。

该文件包含所有与外界发送和接收的文本消息...(但文本必须通过二进制控制字符提取)..所有文本消息均清晰可见...以^ M字符结尾的行...等

例如:假设^ @ ^ X是控制字符... \\ xaa,十六进制为aa,等等。在我所需的文本提取周围加载了它们。

^@^@^@^@^@^@^@^@^@^@^@BLLBBCC^X^X^X^X^X^X^X^X^X
^X^X^X
MVT^M
EA1123 TEXT TEXT TEXT^M
END^M
\xaa^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
 ^@^@^@^@^@^@^@^@^@^@^@TTBBTT^X^X^X^X^X^X^X^X^X
   ^X^X^X blah blah blah... of control characters.. and then the message comes..
   MVT MESSAGE 2
   ED1123
   etc.

等等..对于一些消息。

使用Perl ..很容易做到:

while (<>) {
  use regular expression to split messages
  m/   /


}

如何在python中轻松做到这一点。

  1. 如何读取文件? 二进制和文本穿插
  2. 消除不必要的控制字符
  3. 解析两个\\ xaa有用文本信息\\ xaa之间的消息(十六进制'aa')
  4. 打印出所需的东西
  5. 循环浏览所有行..和更多文件。

在文本文件示例中……我感兴趣的是……BLLBBCC……以及MVT和EA1123等。

请协助...如果在python中将非常困难..我将不得不仔细考虑perl本身的逻辑..因为它(perl)至少在循环部分不会给我带来很多错误二进制和文本的东西..和正则表达式。

谢谢。

阅读您的答案/评论后更新02 Jan

经过S.Lott的评论和其他...之后,我在这里..,并且可以正常工作80%。

import fileinput
import sys
import re

strfile = r'C:\Users\' \
          r'\Learn\python\mvt\sitatex_test.msgs'

f = open(strfile, 'rb')

contents = f.read() # read whole file in contents

#extract the string between two \xaaU.. multiline pattern match
#with look ahead assertion
#and this is stored in a list with all msgs
msgs = re.findall(r'\xaaU.*?(?=\xaaU)', contents, re.I|re.DOTALL|re.M)

for msg in msgs:
    #loop through msgs.. to find the first msg then next and so on.
    print "## NEW MESSAGE STARTS HERE ##"

    #for each msg split the lines.. to read line by line
    # stored as list in msglines
    msglines = msg.splitlines()
    line = 0
#then process each msgline with a message
for msgline in msglines:
    line += 1
    #msgline = re.sub(r'[\x00]+', r' ', msgline)
    mystr = msgline
    print mystr
    textstrings = re.findall(r'[\x00\x20-\x7E]+', msgline)

到目前为止还不错..我还没有完全完成..因为我需要逐行和逐字地解析文本..(例如)提取原始地址和标题,主题行,消息正文。通过控制字符来解析消息。

现在,我被困在...如何逐行打印转换为\\x00\\x02..等(使用\\xHH格式)的控制字符..却不打扰普通可读文本。

例如..说我有这个:假设^@^X是一些控制字符line1 = '^@UG^@^@^@^@^@^@^@^@^@^@BLLBBCC^X^X^X^X^X^X^X^X^X' (在第一行)。

当我在IDLE ..上打印该行时.. print line1 ..它只说前2或3个字符..并忽略其余字符,因为控制字符被阻塞。

但是,当我用以下命令print re.findall(r'.*', line1)时: print re.findall(r'.*', line1)

['\xaaUG\x02\x05\x00\x04\x00\x00\x00\x05\x00\x00\x00....
x00\x00\x00..BLLBBCC\x00\x00N\x00N\\x00
 002 010 180000 DEC 11', '']

它将所有控制字符转换为\\ xHH格式..并完整保留ascii文本..(正如我想要的那样)..列表中有两个项目..最后带有“。”,打印效果很好。

  1. 最后对空字符串的解释是什么?
  2. 如何避免它...我只是希望将行很好地转换为字符串(而不是列表)。 例如,一行二进制/文本将被转换为带有\\ xHH代码的字符串..单独保留ASCII TEXT。

使用re.findall(r'.*', line1)是唯一简单的解决方案..进行此转换..或是否有任何其他直接的方法..将'\\x00string'转换为\\ xHH和TEXT(其中它是可打印的字符或空白)。

还..任何其他有用的意见,以使线条很好。

谢谢。

更新2Jan2011-第2部分

我发现re.findall(r'.+', line1)剥离到

['\xaaUG\x02\x05\x00\x04\x00\x00\x00\x05\x00\x00\x00....
    x00\x00\x00..BLLBBCC\x00\x00N\x00N\\x00
     002 010 180000 DEC 11']

列表中没有多余的空白''项目。 这一发现经过无数次反复试验。

我仍然需要帮助才能完全消除该列表,但只返回一个字符串。 像这样:

'\xaaUG\x02\x05\x00\x04..BLLBBCC..002 010 180000 DEC 11'

在05Jan上添加了信息:

@约翰·马钦

1)\\ xaaU是消息之间的分隔符..在示例中..我可能在示例中已经忽略了。 请参阅以下有关以\\ xaaU结尾(但未列出)的实际消息。 从repr( r'\\xaaU.*?(?=\\xaaU)'之间的msg)获得以下文本

我正在尝试理解二进制格式..这是一条典型的消息,它是从第一个'JJJOWXH'发送出去的,它是发送方地址..后面跟有7个字母数字的任何内容都是接收方地址..基于发送方地址..我知道这是'SND'还是'RCV'..因为来源是'JJJOWXH'...这个味精是'SND',就像我们是'JJJOWXH'。

该消息已发送至:JJJKLXH .... JJJKRXH ....等。

所有.. \\ x00000000完成后.. sita头文件和主题开始在这种特殊情况下... "\\x00QN\\x00HX\\x00180001 \\x00"这是头文件。我只对之间的所有内容感兴趣\\ x00。

并在下一个\\ .00或任何其他控制字符之后出现主体。在这种情况下,它是:

COR \\ r \\ nMVT \\ r \\ nHX9136 / 17.BLNZ.JJJ \\ r \\ nAD2309 / 2314 EA0128 BBB \\ r \\ nDLRA / CI / 0032/0022 \\ r \\ nSI EET 02:14 HRS \\ r \\ n RA / 0032 DUE延迟ARVL ACFT \\ r \\ n CI / 0022卸载悬空托盘,由于包装不足导致\\ r \\ n空间问题

一旦可读文本结束...出现在第一个\\ xaaU之前的第一个控制字符将被忽略...在上述情况下,“空格问题”是最后一个..然后控制字符开始...因此可以忽略...有时直到下一个\\ xaaU都没有控制字符。

这是一条完整的消息。

“ \\ xaaU \\ x1c \\ x04 \\ x02 \\ x00 \\ x05 \\ x06 \\ x1f \\ x00 \\ x19 \\ x00 \\ x00 \\ x00 \\ xc4 \\ x9d \\ xedN \\ x1a \\ x00?\\ x02 \\ x02 \\ x00 \\ x00B \\ x02 \\ x02 \\ x00E \\ x02 \\ x07 \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00M \\ x02 \\ xec \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ x00 \\ x00?\\ x02M \\ x02 \\ xec \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00 \\ xff \\ xff \\ x00 \\ x00:\\ x03 \\ x10 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x00 \\ x7f \\ x00JJJOWXH \\ x00 \\ x05w \\ x01x \\ x01 \\ x00 \\ x01JJJKLXH \\ x00 \\ x00 \\ x7f \\ x01 \\ x80 \\ x01 \\ x00 \\ x01 \\ x01JJKRXH \\ x00F \\ x87 \\ x88 \\ x01 \\ x00 \\ x01JJJFFXH \\ x00 \\ xff \\ x8f \\ x01 \\ x90 \\ x01 \\ x00 \\ x01JJJFCXH \\ x00 \\ xff \\ x97 \\ x01 \\ x98 \\ x01 \\ x00 \\ x01JJJFAXH \\ x00 \\ x00 \\ x9f \\ x01 \\ xa0 \\ x01 \\ x00 \\ x01JJJKPXH \\ x00 \\ x00 \\ xa7 \\ x01 \\ xa8 \\ x01 \\ x00 \\ x01 \\ x01HAKUOHU \\ x00 \\ x00 \\ xaf \\ x01 \\ xb0 \\ x01 \\ x00 \\ x01BBBHRXH \\ x00 \\ x00 \\ xb7 \\ x01 \\ xb8 \\ x01 \\ x00 \\ x01BBBFFHX \\ x00 \\ x00 \\ xbf \\ x01 \\ xc0 \\ x01 \\ x00 \\ x01 \\ x01BBBOMHX \\ x00 \\ x00 \\ xc7 \\ x01 \\ x01 \\ x01 \\ x00 \\ x01BBBFMXH \\ x00 \\ x00 \\ xcf \\ x01 \\ xd0 \\ x01 \\ x00 \\ x01 \\ x01JJJHBER \\ x00 \\ x00 \\ xd7 \\ x01 \\ xd8 \\ x01 \\ x00 \\ x01BBBFRUO \\ x00 \\ x00 \\ xdf \\ x01 \\ xe0 \\ x01 \\ x00 \\ x01BBBKKHX \\ x00 \\ x00 \\ xe7 \\ x01 \\ xe8 \\ x01 \\ x00 \\ x01JJJLOTG \\ x00 \\ x01 \\ xef \\ x01 \\ xf0 \\ x01 \\ x00 \\ x01JJJLCTG \\ x00 \\ x00 \\ x00 \\ xf7 \\ x01 \\ xf8 \\ x01 \\ x01 \\ x00 \\ x01HDQOMTG \\ x005 \\ xff \\ x01 \\ x00 \\ x02 \\ x00 \\ x01CHACSHX \\ x00K \\ x07 \\ x02 \\ x08 \\ x02 \\ x00 \\ x01JJJKZXH \\ x00F \\ x0f \\ x02 \\ x10 \\ x10 \\ x02 \\ x00 \\ x01BBBOMUO \\ x00 \\ x17 \\ x10 \\ x18 \\ x02 \\ x00 \\ x01BBBORXH \\ x00 \\ x1f \\ x02 \\ x02 \\ x00 \\ x01BBBOPXH \\ x00W'\\ x02(\\ x02 \\ x00 \\ x01CHACSHX \\ x00 / \\ x020 \\ x02 \\ x00 \\ x00 \\ x01JJJDBXH \\ x0007 \\ x028 \\ x02 x00010000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00 \\ x00000000 \\ x00QN \\ x00HX \\ x00180001 \\ x00COR \\ r \\ nMVT \\ r \\ nHX9136 / 17.BLNZ.JJJ \\ r \\ nAD2309 / 2314 EA0128 BBB \\ r \\ nDLRA / CI / 0032/0022 \\ r \\ nSI EET 02:14 HRS \\ r \\ n RA / 0032由于迟到的ARVL ACFT \\ r \\ n CI / 0022卸载了悬空的托盘由于不适当的包装领导到\\ r \\ n空间问题\\ x00D- \\ xedN \\ x00 \\ x04 \\ x1a \\ x00t <\\ x93 \\ x01x \\ x00M_ \\ x00”

2)在知道'repr'之后,我不再使用。+了。

3)每条消息都是多行的..我需要保留所有控制字符以使这种专有格式有意义。这就是为什么我需要repr才能近距离查看它。

希望这能解释...这只是文件中每1000条中的1条消息...有些是'SND',有些是'RCV'...对于'RCV'不会有'000000'。偶尔会有一些例外情况...但是通常没关系。

任何人的任何进一步建议..我仍在处理文件..完整地检索文本...具有发送者和接收者的地址。

谢谢。

问:如何读取文件? 二进制和文本穿插

答:不用理会,只需将其阅读为普通文本即可,并且可以保持二进制/文本二分法(否则您将无法轻松对其进行正则表达式处理)

fh = open('/path/to/my/file.ext', 'r')
fh.read()

万一您出于某种原因以后想要读取二进制文件,只需将ab添加到open的第二个输入中:

fh = open('/path/to/my/file.ext', 'rb')

问:消除不必要的控制字符

答:使用python re模块。 您的下一个问题有点问如何

问:解析两个\\ xaa有用的文本信息\\ xaa之间的消息(十六进制'aa')

答:re模块具有findall函数,该函数按您(通常)的预期工作。

import re

mytext = '\xaaUseful text that I want to keep\xaa^X^X^X\xaaOther text i like\xaa'
usefultext = re.findall('\xaa([a-zA-Z^!-~0-9 ]+)\xaa', mytext)

问:打印出所需的东西

* A:有打印功能...

print usefultext

问:循环浏览所有行..和更多文件。

fh = open('/some/file.ext','r')

for lines in fh.readlines():
    #do stuff

我让您找出os模块,找出存在的文件/如何遍历它们。

Python也支持正则表达式。 我不会说Perl,所以我不知道您的Perl代码到底是做什么的,但是这个Python程序可能会帮助您:

import re
with open('yourfile.pst') as f:
    contents = f.read()
textstrings = re.findall(r'[\x20-\x7E]+', contents)

这将为您提供文件中一个或多个ASCII可打印字符的所有字符串的列表。 那可能并不是您想要的,但是您可以从那里对其进行调整。

请注意,如果您使用的是Python 3,则必须担心二进制数据和文本数据之间的区别,它将变得更加复杂。 我假设您使用的是Python 2。

你说:

我仍然需要帮助才能完全消除该列表,但只返回一个字符串。 像这样

换句话说,您具有foo = [some_string]并且您正在执行print foo ,它的一面确实是repr(some_string)但将其括在不需要的方括号中。 因此,只需print repr(foo[0])

似乎有些原因无法解释:

  1. 您说有用的文本用\\xaaU括起来,但是在示例文件中,开始位置附近只有\\xaa (缺少U ),而不是该分隔符的2次出现。

  2. 你说

    我发现re.findall(r'。+',line1)条带到...

    实际上,这是剥离\\n (而不是\\r !!)-我认为尝试恢复电子邮件时应该保留换行符。

     >>> re.findall(r'.+', 'abc\\r\\ndef\\r\\n\\r\\n') ['abc\\r', 'def\\r', '\\r'] 

    您使用\\r字符做了什么? 您是否测试了多行消息? 您是否测试了多消息文件?

  3. 剩下的就是猜测谁或什么打算消耗您的输出。 你写

    我需要逐行和逐词解析文本

    但是您似乎过于担心使用\\xab而不是乱码来“清晰地”打印消息。

  4. 看起来您最新代码中的最后6行左右( for msgline in msglines:等等)应该缩进一个级别。

是否可以澄清以上所有内容?

暂无
暂无

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

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