2016-10-03 3 views
-2

私はPython 2からPython 3に私のpythonアプリケーションの変換を行っています。私が使用する関数の1つは、バイナリファイルから印刷可能な文字を取得することです。私は以前のpython 2に次の関数を使用し、それは素晴らしい仕事:印刷可能なcharctersのみをバイナリファイル(Linuxでは文字列と同等)で印刷する方法は?

import string 

def strings(filename, min=4): 
    with open(filename, "rb") as f: 
     result = "" 
     for c in f.read(): 
      if c in string.printable: 
       result += c 
       continue 
      if len(result) >= min: 
       yield result 
      result = "" 
     if len(result) >= min: # catch result at EOF 
      yield result 

コードPython equivalent of unix "strings" utilityから実際にあります。私は、Python 2と上記のコードを実行すると、それは私のために絶対に大丈夫です、このような出力を生成します

+s 
^!1^ 
i*Q(
}"~ 
%lh!ghY 
#dh! 
!`,! 
mL#H 
o!<XXT0 
' < 
z !Uk 
% 
wS 
n` !wl 
*ty 

(Q 6 
!XPLO$ 
E#kF 

しかし、関数はPythonの3の下に奇妙な結果を与えることがエラーを生成します。

TypeError: 'in <string>' requires string as left operand, not int 

は、だから私はこの

でこれ

if c in string.printable: 

を置き換えることによって 'STR' から 'int型' に変換しました私は、Python 3を使用する場合、私は任意の文字を参照してくださいカント

56700 
0000000000000000000000000000000000000000 
1236 
60000 
400234 
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
2340 
0000 
5010 
5000 
17889 
2348 
23400000000 
5600 

(私も同じエラーメッセージがスローされたすべての場所を変換)

今のpython 3は次のような出力を提供します。コードが動作するか、またはソリューションへのポインタを取得するための任意の助けに感謝します。私が必要とするのは、バイナリファイル(数kbの非常に小さい)から文字列を抽出し、それを変数に格納することです。

+0

あなたはpython3でバイトを持っています。 'set(string.printable.encode()) 'を使う –

+0

誰がこの質問に投票したのかわからない。しかし、私はMartijn Pieters氏の答えに書かれた説明と説明を提示するように要請します。表示されている場合、私はこの投稿/質問を削除します。 –

答えて

2

バイナリモードでファイルを開くと、結果はbytesになります。 bytesオブジェクトを反復すると、の整数が得られ、0〜255の範囲の文字ではありません。bytes documentationから:

While bytes literals and representations are based on ASCII text, bytes objects actually behave like immutable sequences of integers, with each value in the sequence restricted such that 0 <= x < 256

変換string.printableことに対してセットとテストに:

printable = {ord(c) for c in string.printable} 

if c in printable: 

次は、合理的に物事を保つためにbytesarray()オブジェクトに追加しますASCIIからデコードしてstrという結果を生成します。

printable = {ord(c) for c in string.printable} 

with open(filename, "rb") as f: 
    result = bytearray() 
    for c in f.read(): 
     if c in printable: 
      result.append(c) 
      continue 
     if len(result) >= min: 
      yield result.decode('ASCII') 
      result.clear() 
    if len(result) >= min: # catch result at EOF 
     yield result 

は1でバイト1を反復処理するのではなく、あなたの代わりにない印刷可能であるものに分割することができます:

import re 

nonprintable = re.compile(b'[^%s]+' % re.escape(string.printable.encode('ascii'))) 

with open(filename, "rb") as f: 
    for result in nonprintable.split(f.read()): 
     if result: 
      yield result.decode('ASCII') 

私はチャンクでではなく、一つでファイルを読み込む探求したいです行く; 1でメモリに大きなファイルをフィットしようとしないここに行く:

with open(filename, "rb") as f: 
    buffer = b'' 
    for chunk in iter(lambda: f.read(2048), b''): 
     splitresult = nonprintable.split(buffer + chunk)    
     buffer = splitresult.pop() 
     for string in splitresult: 
      if string: 
       yield string.decode('ascii') 
    if buffer: 
     yield buffer.decode('ascii') 

バッファは1つのチャンクから次への不完全な単語の上に運びます。 re.split()は、開始時および終了時に空の値を生成します。

+0

そして 'result = b" "'も使用してください。 –

+0

@ MarkTolonen:「bytearray」をよく使う。 'byte'オブジェクトに整数を追加することはできません。 –

+0

true、それはそれらの驚くべき事の一つです。 'str'を繰り返して長さ1 strsを取得しますが、' bytes'を反復して整数を取得します。 「bytearray」は、とにかく変更可能な意味合いが増します。 'result + = bytes([c])'は動作しますが、あまり効率的ではありません。 –

-1

これはうまくいくと確信しています。ジェネレータとして

:関数として

import string, _io 
def getPrintablesFromBinaryFile(path, encoding='cp1252'): 
    global _io, string 
    buffer = _io.BufferedReader(open(path, 'rb')) 
    while True: 
     byte = buffer.read(1) 
     if byte == b'': 
      return #EOF 
     try: 
      d = byte.decode(encoding) 
     except: 
      continue 
     if d in string.printable: 
      yield d 

だけ反復可能にgetPrintablesFromBinaryFile()の出力を収集することです。

説明:

  1. のインポートに必要なモジュール
  2. それがある場合
  3. はバッファ
  4. チェックからバイトを取得し、バッファ
  5. を作成したモジュール
  6. ロード関数を定義EOF
  7. 「はい」の場合は、発電機を停止してください
  8. エンコーディングを使用して復号化しようとし得、それは印刷可能
  9. 印刷可能な場合にはできません、
  10. 不可能であれば(等'\xef'はUTF-8を使用してデコードしない)こと

注:cp1252多くのテキストファイルのエンコーディングです

+0

なぜ 'io'ではなく' _io'を使うのですか?そして 'open()'は既にバッファリングされた読者を返します、なぜこれをもう一度閉じてください?なぜ任意の8ビットコーデックでデコードするのですか? 'string.printable'中の全ての文字はASCII文字です。復号化の前にこれらを検出し、そのオーバーヘッドを避ける方がよい。一度に1バイトだけを読み込むので、マルチバイトコーデックを使用することはできません*とにかく*;テキストモードでファイルを開く方がより論理的でした。また、ブランケットの 'except'文も使用しないでください。代わりに特定の例外をキャッチします。 OPコードは文字列全体を生成し、個々のバイトを生成しますが、これは役に立ちません。 –

関連する問題