2017-12-14 2 views
-1

テキストファイルを開き、RECORD-FEBで始まる行をスキャンします。行がRECORD-FEBで始まっている場合は、大文字の後に大文字を2つ(番号1と呼ぶ)、その後にリテラル$--、次に別の番号(番号2と呼ぶ)を探したい。 number1がnumber2と等しい場合は、その行の先頭に「@」記号を追加して行番号を返します。そうでない場合は、そのまま続行します。マッチした行でテキストファイルをスキャンする2つの番号を持つ文字列を探します

サンプルパターン:それはどちらの結果もエラーを与えていない:

AB566$--12 Invalid case 
RT21$--9 Invalid Case 
TP667$--677 Valid case 

私の問題はre.searchが動作していないということです。基本的に私のabc機能が動作していません。ファイル名.txtの

import re 
def main(): 
    with open(r"filename.txt") as f: 
     for line in f: 
      if "RECORD-FEB" in line: 
      # print(line) 
       abc(line) 

def abc(line): 
    case = re.search(r"\[A-Z]{2}\d+\[$][--]\d+",line) 
    if case: 
     print(line) 
     # code to append @ at beginning of that line and return line number 
main() 

コンテンツは、このようなものです:

abcd efg avcd AB566$--12 pqrs 
RECORD-FEB MB566$--12 abcd efgh lmno 
     RECORD-FEB FREWREWRE EWRRWERE AB566$--12 EREWWRRW 
+0

だから、問題は何でしょうか。あなたの質問を書いていないか、私たちがあなたの心を読むことを期待しているかのように見えます。 –

+0

関連する入力テキストを入力してください。 – dawg

+0

あなたはどんな出力を期待していますか?何がうまくいかないのですか?エラーが発生していますか?もしそうなら、それを投稿してください。できればスタックトレースを付けてください。 –

答えて

0

基本的な正規表現の問題

あなたのコードの最大の問題は、あなたの通常のバックスラッシュと角括弧の無償使用であり、表現。それとは別に、あなたは基本的にあなたの問題を正しく解決しようとしています。

バックスラッシュは通常、特殊文字をリテラルにし、通常の文字に特別な意味を与えます。 \[を実行するたびに、あなたは特定のアプリケーションでは決してしたく​​ないリテラルの開き括弧と一致します。

大括弧はリテラル文字列を示しません。彼らは文字クラスを設定します。つまり、角括弧内の文字は文字列内の対応する文字と一致することができます。具体的には、[--]はリテラルの二重ダッシュを意味しません。それは、「ダッシュまたはダッシュのいずれかの文字」を意味し、冗長であり、あなたが望むものではありません。

r"\[A-Z]{2}\d+[$][--]\d+"をはるかに簡単にr"[A-Z]{2}\d+\$--\d+"に変更する必要があります。必要な文字クラスは、大文字の場合は[A-Z]です。必要なエスケープされた特殊文字は\$で、EOLの一致ではなくリテラルドル記号を取得します。

キャプチャ番号

は数字を比較することができるようにするには、あなたの試合の一部をキャプチャする必要があります。これを行うには、括弧を使用してキャプチャグループをマークします。正規表現はr"[A-Z]{2}(\d+)\$--(\d+)"のようになります。

数値のテキスト表現を変換する必要はありません。文字列が一致しない場合、一致しません。

コンパイルする正規表現

今、あなたのループの反復ごとにre.searchを使用しています。これは、ファイル内のすべての行について正規表現を最初からコンパイルします。小さなファイルでは大したことではありませんが、は大きなファイルに違いがあります。

一般に、正規表現を複数回適用する場合は、re.compileを使用して事前コンパイルすることを検討してください。コンパイルされたregexオブジェクトでsearchメソッドを使用できます。これは同じ方法で動作しますが、はるかに高速です。

行番号

ファイルを反復処理するときenumerateでファイルイテレータをラップ、行番号を取得するには:

for num, line in enumerate(file): 
    ... 

あなたがそこにあれば返却されるように、abcに行番号を渡すことができます一致している、またはより良いまだ、あなたは完全にabcを排除することができます。原則としてライン

先頭に追加した要素は、インプレースファイルを変更することは現実的ではありません。ファイルは、ディスク上のバイトの集合です。 @文字をファイルの任意の場所に挿入する場合は、残りのバイトをすべて移動する必要があります。代わりに、通常、変更したい行を除いて、すべての行が同じである別のファイルに書き込みます。挿入がシームレスに見えるようにするには、完了したら元のファイルを上書きするために結果のファイルを移動します。

これは、出力ファイルを開く必要がありますを意味します。パターンに一致するすべての行に接頭辞@が書き込まれます。他のすべての行はそのまま渡されます。上記のすべてを組み合わせる

コード

、あなたはこのような何かを得る:それはあまりをしないので、私はabc機能を取り除く得ている

import re 

def main(): 
    pattern = re.compile(r"[A-Z]{2}(\d+)\$--(\d+)") 
    matches = [] 
    with open(r"filename.txt") as f, open(r"filename.txt.out", "w") as out: 
     for num, line in enumerate(f): 
      if line.strip().startswith("RECORD-FEB"): 
       case = pattern.search(line) 
       if case and case.group(1) == case.group(2): 
        matches.append(num) 
        line = '@' + line 
      print(line, file=out) 
    print(matches) 

main() 

を。すべて一致する行番号number1 == number2がリストに追加されますmatches、最後に表示されます。あなたが完了した後、元のファイルを上書きする場合

は、次の操作を行います。

import shutil 

... 
    shutil.move("filename.txt.out", "filename.txt") 
関連する問題