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

时间:2011-12-27 16:37:04

标签: python perl text-extraction

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

这实际上相当于SITATEX Application(来自SITA)的outlook .pst文件。

该文件包含所有发送和接收来自外部世界的文本消息...(但文本必须通过二进制控制字符提取)..所有文本消息都清晰可用...带行结束^ M个字符......等等。

例如:假设^ @ ^ X是控制字符... \ xaa和HEX 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(HEX&#39; aa&#39;)
  4. 打印出所需的内容
  5. 遍历所有行...以及更多文件。
  6. 在文本文件示例中......我有兴趣看到.. BLLBBCC ...以及MVT和EA1123等等。

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

    感谢。

    在阅读完答案/评论后更新02Jan

    在浏览了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)
    

    到目前为止一直这么好..我仍然没有完全完成..因为我需要逐行逐字解析文本..以拾取(作为示例)原始地址和标题,主题行,消息body ...通过控制字符解析消息。

    现在我不知道......如何逐行打印转换为\x00\x02..等控制字符(使用\xHH格式)...但是保留正常的可读文本。< / p>

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

    当我在IDLE上打印该行时,print 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文本完好无损..(正如我想要的那样)..有一个捕获..列表有两个项目..用&#39; &#39;最后。

    1. 最后对空字符串的解释是什么?
    2. 如何避免它......我只想将线路很好地转换为字符串(不是列表)。即一行二进制/文本要转换为带有\ xHH代码的字符串。只留下ASCII文本。
    3. 使用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']
      

      没有额外的空白&#39;&#39;列表中的项目。经过多次试验和错误后,这一发现。

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

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

      在05Jan上添加了信息:

      @John Machin

      1)\ xaaU是消息之间的分隔符..在示例中..我可能刚刚在示例中省略了。请参阅下面的一条以\ xaaU结尾的实际消息(但遗漏了)。 以下文本来自repr(r'\xaaU.*?(?=\xaaU)'之间的消息)

      我正在尝试理解二进制格式..这是一个发送的典型消息 第一个&#39; JJJOWXH&#39;是发件人地址..后面有7个字母数字的接收器地址。基于发件人地址..我可以知道这是一个&#39; SND&#39;或者&#39; RCV&#39; ..作为来源是&#39; JJJOWXH&#39; ...这个消息是&#39; SND&#39;因为我们是JJJOWXH&#39;。

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

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

      并且身体接下来..在最后的\ x00或任何其他控制角色之后......在这种情况下......它是:

        

      COR \ r \ n \ 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 OFFLOAD OVERHANG PALLET DUE INADQUATE   包装导致\ r \ n空间问题

      一旦可读文本结束...出现的第一个控制字符,直到结束\ xaaU被忽略...在上述情况下......&#34;空格问题&#34; ..是最后一个。然后控制字符开始......所以要忽略......有时控制字符不存在,直到下一个\ xaaU。

      这是一条完整的信息。

        

      &#34; \ xaaU \ X1C \ X04 \ X02 \ X00 \ X05 \ X06 \ X1F \ X00 \ X19 \ X00 \ X00 \ X00 \ XC4 \ x9d \ xedN \ X1A \ X00 \ X02 \ X02 \ 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 \ 0x7F部分\ x00JJJOWXH \ X00 \ x05w \ x01x \ X01 \ X00 \ x01JJJKLXH \ X00 \ X00 \ 0x7F部分\ X01 \ X80 \ X01 \ X00 \ x01JJJKRXH \ x00F \的x87 \ X01 \ 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 \ x01HAKUOHU \ X00 \ X00 \ XAF \ X01 \ XB0 \ X01 \ X00 \ x01BBBHRXH \ X00 \ X00 \ XB7 \ X01 \ XB8 \ X01 \ X00 \ x01BBBFFHX \ X00 \ X00 \ XBF \ X01 \ XC0 \ X01 \ X00 \ x01BBBOMHX \ X00 \ X00 \ xc7 \ X01 \ xc8 \ X01 \ X00 \ x01BBBFMXH \ X00 \ X00 \ XCF \ X01 \ XD0 \ X01 \ X00 \ 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 \ XF7 \ X01 \ XF8 \ X01 \ X00 \ x01HDQOMTG \ X005 \ XFF \ X01 \ X00 \ X02 \ X00 \ x01CHACSHX \ x00K \ X07 \ X02 \ X08 \ X02 \ X00 \ x01JJJKZXH \ x00F \ X0F \ X02 \ X10 \ X02 \ X00 \ x01BBBOMUO \ X00   \ x17 \ x02 \ x18 \ x02 \ x00 \ x01BBBORXH \ x00 \ x1f \ x02   \ X02 \ X00 \ x01BBBOPXH \ x00W&#39; \ X02(\ X02 \ X00 \ x01CHACSHX \ X00   / \ X020 \ X02 \ 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 OFFLOAD OVERHANG PALLET DUE INADQUATE   包装领先于\ r \ n空间   问题\ x00D- \ xedN \ X00 \ X04 \ X1A \ x00t&LT; \ X93 \ x01x \ x00M_ \ X00&#34;

      2)我没有使用。+再次使用&#39; repr&#39;众所周知。

      3)每条消息都是多行的..我需要保留所有的控制字符,以便对这种专有格式有所了解。这就是为什么我需要repr才能看到它。

      希望这可以解释......这只是文件中1000条中的1条消息...而且有些是&#39; SND&#39;还有一些是RCV&#39; ......以及RCV&#39;不会有&00; 000000&#39; ..偶尔会有规则的小例外......但通常都可以。

      任何进一步的建议任何人..我仍在使用该文件..以完整的方式检索文本...包含发件人和收件人地址。

      谢谢。

3 个答案:

答案 0 :(得分:2)

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

答:不要打扰,只需将其作为普通文本阅读,您就可以保持二进制/文本二分法(否则您将无法轻易地对其进行正则表达式)

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

如果您因某种原因想要稍后阅读二进制文件,只需在打开的第二个输入中添加一个b:

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

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

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

问:在两个\ xaa有用的文本信息之间解析消息\ xaa(HEX'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模块,找出存在哪些文件/如何迭代它们。

答案 1 :(得分:2)

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。

答案 2 :(得分:1)

你说:

  

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

换句话说,你有foo = [some_string]并且你正在做print foorepr(some_string)作为一方做print repr(foo[0]),但将其用方括号括起来,你不想要。所以只需\xaaU

似乎有几件事无法解释:

  1. 您说有用的文字被\xaa括起来,但在示例文件中,而不是该分隔符的两次出现,在开头附近只有U(缺少\n) ,别无其他。

  2. 你说

      

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

    这实际上是剥离\r(但不是>>> re.findall(r'.+', 'abc\r\ndef\r\n\r\n') ['abc\r', 'def\r', '\r'] !!) - 我认为在尝试恢复电子邮件时,换行符值得保留。

    \r

    你对\xab个字符做了什么?你测试了多行消息吗?您是否测试了多消息文件?

  3. 可以猜测是谁或什么意图消耗你的输出;你写的

      

    我需要逐行逐字解析文本

    但你似乎过分担心用“清晰”打印信息。 <{1}}而不是胡言乱语。

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

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