『退屈なことはPythonにやらせよう』その6 (8章ファイル操作)

Python初心者です。『退屈なことはPythonにやらせよう』を走っています。

6回目の今回は、8章をやっていきます~。

前回の記事はこちら↓

8章は「ファイル操作」になります。

前回の記事でも書いていますが、だんだんと課題プロジェクトが重くなってきたので、今回はそちらをメインに書いていきます。

8章では主に

  • ファイルパス
  • osモジュール
  • open関数
  • shelveモジュール

について学びました。

これらを生かして、課題プロジェクトに取り組んでいきます。

今回の目次


マルチクリップボードの拡張

課題のクリア条件

マルチクリップボードを作る

必要な機能は以下の通り

コマンドプロンプトまたはターミナル上で、

「py mcb.py <command> <keyword>」

とすると、クリップボード中コピーされたものをキーワードに紐づけて格納できるコードです。

<command>を指定せずに<keyword>のみを指定すると、そのキーワードに紐づけされたものがクリップボードにコピーされます。(Ctrl-Vで張り付けられるようになる。)

機能としては、(command)

  • save <keyword> : keywordに紐づけて、現在クリップボード上にあるものを格納
  • <keyword> : keywordに紐づけて格納された文字列をクリップボードに格納
  • list : ここまでに保存したkeywordの一覧を表示
  • delete <keyword> : 指定された<keyword>に格納された値を削除
  • delete : すべてのkeywordを削除
#! python3
# mcb_d.pyw - クリップボードのテキストを保存・復元
# Usage:
# py.exe mcb_d.pyw save <keyword>  -  クリップボードをキーワードに紐づけて保存
# py.exe mcb_d.pyw <keyword>  -  キーワードに紐づけられたテキストをクリップボードにコピー
# py.exe mcb_d.pyw list  -  全キーワードをクリップボードにコピー
# py.exe mcb_d.pyw delete <keyword>  -  キーワードを削除
# py.exe mcb_d.pyw delete   -   全キーワードを削除


import shelve, pyperclip, sys

mcb_shelf = shelve.open("mcb")

#クリップボードの内容を保存
if len(sys.argv) == 3 and sys.argv[1].lower() == "save":
    mcb_shelf[sys.argv[2]] = pyperclip.paste()
#クリップボードの内容を削除
elif len(sys.argv) == 3 and sys.argv[1].lower() == "delete":
    print(sys.argv[2]+"を削除しました")
    del mcb_shelf[sys.argv[2]]
elif len(sys.argv) == 2:
    #キーワード一覧と、内容の埋め込み
    if sys.argv[1].lower() == "list":
        pyperclip.copy(str(list(mcb_shelf.keys())))
    elif sys.argv[1].lower() == "delete":
        mcb_shelf.clear()
    elif sys.argv[1] in mcb_shelf:
        pyperclip.copy(mcb_shelf[sys.argv[1]])
    
mcb_shelf.close()

最も苦労したところは、コマンドプロンプト上で実行することでした。

結局、コマンドプロンプト上で動いているPythonのLibフォルダに、pyperclipのファイルを手動で動かしたらなんとか回りました。

他にもいろいろやってしまっていて、これが決定打になったかどうかは確認できていないので、次にサードパーティ製のパッケージを使う時に試してみたいと思います。


作文ジェネレータ

課題のクリア条件

任意の「.txt」ファイルを受け取って、その中から

  • “ADJECTIVE”
  • “NOUN”
  • “ADVERB”
  • “VERB”

を見つけ出し、それぞれを置換する単語をユーザーから受け取ります。

その後、受け取った単語で作った文章を表示し、結果を新たなテキストファイル「.txt」として保存します。

# !python3
# sentence_generator.py  -  テキストファイルを受け取って、"ADJECTIVE", "NOUN", "ADVERB", "VERB"を見つけ出し、任意の単語に置換する。

# Usage
# py sentence_generator.py <.txt file>

import re
import sys

#ファイルの読み込み
read_file = open(sys.argv[1], "r")
read_data = read_file.read()
read_file.close()


#正規表現の探索
regex = re.compile(r"ADJECTIVE|NOUN|ADVERB|VERB")
while True:
    mo = regex.search(read_data)
    if not mo:
        break    
    
    #マッチした部分を教えて、代替の単語を入力してもらう
    if mo.group().lower() == ("adjective" or "adverb"):
        print("Enter an " + mo.group().lower() + ":")
        repl = input()
        
    else:
        print("Enter a " + mo.group().lower() + ":")
        repl = input()
        
    #マッチしたオブジェクトを置き換え
    read_data = read_data.replace(mo.group(), repl, 1)
    
print(read_data)

#渡された単語に置換して新しいテキストファイルに保存
write_file = open((sys.argv[1]).replace(sys.argv[1][-4:], "_gen.txt"), "w")
write_file.write(read_data)
write_file.close()

ちなみに、課題のテキストファイルはこちら。

The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN was unaffected by these events.

コピーしてメモ帳に「プレーンテキストとして張り付け」をして、任意のファイル名.txtとして使っていただければ大丈夫なはずです。

if 文中で使うorの落とし穴

上記のコードを書く中で使った if 分の条件分岐でハマった落とし穴です。なぜか、nounの場合にもadverbまたはadjective用に指定したifの分岐に落ちることがありました。

そこで、正しく分岐に進んでない理由をさぐるために、以下のようなコードを試してみました。

>>> "noun" == "adverb" or "adjective" 
'adjective'

>>> "noun" == "adverb", "adjective"   
(False, 'adjective')

どうやら、真の場合には”adverb”(orの左側)、偽の場合には”adjective”(orの右側)が出力されてしまうみたいなのです。


これをどうすれば、”noun”が”adverb”または”adjective”である、の条件式にできるかというと、

>>> "noun" == ("adverb"or"adjective")  
False

()でくくる必要がありました!

いや、お恥ずかしいですね…


正規表現検索

課題のクリア条件

コマンドライン引数として、正規表現パターンを受け取って、カレントディレクトリ中の「.txt」ファイルをすべて開き、中身の文章にその正規表現があるか探します。そして、その正規表現とマッチした部分を文章としてコマンドラインに出力するコードです。

具体的なコードの流れとしては

  • 正規表現パターンを受け取る
  • ディレクトリ中のファイルの取得
  • 取得したファイルの中から「.txt」のファイルを見つける
  • 見つけた「.txt」ファイルの文中から、正規表現にマッチするパターンを見つけ、その行を出力する

という感じになります。

#! python3
# re_search.py  -  フォルダの中のすべての.txtファイルを開いて、ユーザーが指定した正規表現に
#          マッチする行を検索し、結果を画面に表示する
# Usage
# py re_search.py <正規表現(文字列の部分のみ)>

import sys
import os
import re

#正規表現のパターンを受け取る
regex = re.compile(sys.argv[1])
print("受け取った正規表現は" + sys.argv[1] + "です")

#受け取ったディレクトリ中のファイルを取得する
dr = os.getcwd()
file_list = os.listdir(dr)

for file_name in file_list:
    if not file_name.lower().endswith(".txt"):
        continue
    
    print("Checking " + file_name)
    read_file = open(file_name, "r")
    for line in read_file:
        mo = regex.search(line)
        if mo:
            print(file_name + ": " + line, end="")   #結果の出力
    read_file.close()

コマンドラインで渡す引数として、最初のうちは

「r’000-000-0000’」

みたいな形でraw文を渡していたら、うまくいきませんでした。

正しくは str のまま、つまり

「”000-000-0000″」

だけで渡すとちゃんと動きました。


感想

けっこう大変で、割と時間がかかってしまいました。

「str.lower()」の()を忘れて if 文がうまく走らない、みたいなミスに全然気づけない、というガバを連発したので、もっと丁寧に生きていきたいと思います。

次の記事はこちら↓

『退屈なことはPythonにやらせよう』その6 (8章ファイル操作)” に対して2件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です