まえがき
本記事は、Perl で書いたものの Python 移植版です。
(https://qiita.com/okateim/items/4df7ebca399901660072)
同じ内容で言語を変えたときにPV数にどれくらい差がでるのだろうと
気になって同じ内容2言語で書いてみた次第です。
(やっぱり Python のほうがたくさん見られてるみたいです)
Python での変数定義、ファイル読み込み、
および正規表現処理の復習と備忘録を兼ねて記事に残します。
Better な書き方があれば是非ご教授くださいませ。。
なお、今回用いた Python のバージョンは以下のとおりです。
[MBA ~/work/python]$ python --version
Python 3.6.3 :: Anaconda, Inc.
[MBA ~/work/python]$
概要
指定されたファイルを読み込み、
コメント行(# で始まる行)と空行を除いて
標準出力に出力するだけのプログラム remove_comments.py
を書きました。
[MBA ~/work/python]$ cat test.txt
hoge
# hogehoge
# huga
huga
### hugahuga
[MBA ~/work/python]$
[MBA ~/work/python]$ python remove_comments.py test.txt
hoge
huga
[MBA ~/work/python]$
引数がなかったり、2つ以上指定されていた場合はエラー終了します。
指定されたファイルが無い場合もエラー終了します。
(エラーメッセージの雑さは許してください)
[MBA ~/work/python]$ python remove_comments.py test.txt /etc/hosts
Invalid arguments
[MBA ~/work/python]$ python remove_comments.py
Invalid arguments
[MBA ~/work/python]$ python remove_comments.py hoge
hoge: No such file or directory
[MBA ~/work/python]$
コード
以下が実装です。
import sys
import os
import re
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
ERR_MSG = {
'INVALID_ARGS': "Invalid arguments\n",
'FILE_NOT_FOUND': "No such file or directory\n",
}
def main():
check_args()
(_, filename) = sys.argv
with open(filename, "r") as f:
match_pattern = r'^\s*(#.*|)$'
line = f.readline()
while line:
match = re.match(match_pattern, line)
if not match:
print(line, end="")
line = f.readline()
return EXIT_SUCCESS
def check_args():
ARGS_NUM = 2;
if len(sys.argv) != ARGS_NUM:
sys.stderr.write(ERR_MSG['INVALID_ARGS'])
sys.exit(EXIT_FAILURE);
(_, filename) = sys.argv
if not os.path.isfile(filename):
sys.stderr.write(filename + ": " + ERR_MSG['FILE_NOT_FOUND'])
sys.exit(EXIT_FAILURE)
if __name__ == '__main__':
main()
モジュールインポート部分・定数定義部分
import sys
import os
import re
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
ERR_MSG = {
'INVALID_ARGS': "Invalid arguments\n",
'FILE_NOT_FOUND': "No such file or directory\n",
}
import ...
で、プログラム内で使うモジュールをインポートします。
辞書変数 ERR_MSG
で、エラーメッセージを定義しています。
実際は定数定義用のクラス config.py
なんかを作って、それを import
するのがよいと思います。
今回はコードの練習ということで...
引数チェック: check_args()
引数の数の確認および指定されたファイルの存在を確認します。
def check_args():
ARGS_NUM = 2;
if len(sys.argv) != ARGS_NUM:
sys.stderr.write(ERR_MSG['INVALID_ARGS'])
sys.exit(EXIT_FAILURE);
(_, filename) = sys.argv
if not os.path.isfile(filename):
sys.stderr.write(filename + ": " + ERR_MSG['FILE_NOT_FOUND'])
sys.exit(EXIT_FAILURE)
メインルーチン: main()
def main():
check_args()
(_, filename) = sys.argv
with open(filename, "r") as f:
match_pattern = r'^\s*(#.*|)$'
line = f.readline()
while line:
match = re.match(match_pattern, line)
if not match:
print(line, end="")
line = f.readline()
return EXIT_SUCCESS
with open(filename, "r") as f:
で、ファイルを読み出します。書き込みのときは "w"
。
with
を利用することで、処理終了時に自動でファイルの閉じてくれます。
インデントは深くなりますが、便利です。ファイルを開くときは、必ず使うべきです。
f.readline()
で、1行だけ読み出し、変数 line
に格納します。
while line: line = f.readline()
とすることで、1行ずつの読み出しを繰り返します。
match_pattern = r'^\s*(#.*|)$'
で正規表現のパターンを定義し、
match = re.match(match_pattern, line)
として、マッチオブジェクトを得ます。
このパターンにマッチしないものが欲しいので、
if not match:
とします。
マッチしたものが欲しいときは if match:
です。
マッチした部分の文字列が欲しい場合は、マッチオブジェクト match
に対して、
match.group(0)
, match.group(1)
などによって取得します。詳細はここには書きません。
ちなみに、re.match()
は、先頭一致のみマッチします。
文字列のどこかでマッチすればよい場合は re.search()
を使います。
おわりに
Python で、基本的なファイル操作および正規表現操作を実装しました。
久しぶりに Python でコードを書いたので文法やメソッドをかなり忘れていました。。
やはりコードは定期的に書くべきですね(反省)。