パイソン:ファイルの読み取り時に #comment 行を無視する方法
質問
Python で、テキスト ファイルから 1 行を読み取ったところです。行の先頭にハッシュ # が付いているコメントを無視するコードの作成方法を知りたいです。
次のようになるはずだと思います:
for
if line !contain #
then ...process line
else end for loop
しかし、私はPythonを初めて使用するため、構文がわかりません
解決
あなたが使用することができます STARTSWITH()の
など
for line in open("file"):
li=line.strip()
if not li.startswith("#"):
print line.rstrip()
他のヒント
私はあなたが#
文字を見たとき、あなたが全体の行を無視しないことをお勧めします。単に行の残りの部分を無視します。あなたは、文字列のメソッド関数と呼ばpartition
で簡単に行うことができます:
with open("filename") as f:
for line in f:
line = line.partition('#')[0]
line = line.rstrip()
# ... do something with line ...
partition
はタプルを返します:パーティションstring後のパーティションstring、パーティションstring、およびすべての前に、すべてを。だから、[0]
とインデックスで、我々は、パーティションstringの前部分だけを取ります。
編集:
あなたはpartition()
を持っていないのPythonのバージョンを使用している場合は、ここにあなたが使用できるコードがあります:
with open("filename") as f:
for line in f:
line = line.split('#', 1)[0]
line = line.rstrip()
# ... do something with line ...
これは、分割前にすべてのものを保持し、その後、「#」文字の文字列を分割します。 1
引数は1つの分割後.split()
方法停止になります。以来、私たちは、あなたが[0]
引数なしで同じ答えになるだろう(1
にインデックスを付けることで)、0番目のサブストリングをつかんされているが、これは少し速くなるかもしれません。 (私の元のコードから@gnrからのコメントに感謝を簡素化私の元のコードは、正当な理由なく乱雑だった。おかげで、@gnr)
また、単にpartition()
の独自のバージョンを書くことができます。ここでは1と呼ばれるpart()
ます:
def part(s, s_part):
i0 = s.find(s_part)
i1 = i0 + len(s_part)
return (s[:i0], s[i0:i1], s[i1:])
@dalleは「#」の文字列中に現れることに注意しました。それは正しく、このケースを処理することは容易ではありませんので、私はそれを無視し、私は言った何かを持っている必要があります。
入力ファイルは、引用符で囲まれた文字列のためのシンプルな十分なルールを持っている場合は、、これは難しいことではありません。あなたが法的なPythonの引用符で囲まれた文字列を受け入れた場合は、単一引用符で囲まれた、二重引用符で囲まれがあるので、それは難しいだろう、行末、トリプル引用符で囲まれた文字列(単一または二重のいずれかの引用符を使用)をエスケープバックスラッシュで複数行の引用符、およびでも、生のストリングス!複雑なステートマシンになり、正しくすべてを処理するための唯一の可能な方法ます。
しかし、我々は単純な引用符で囲まれた文字列に自分自身を制限している場合、我々は簡単なステートマシンでそれを処理することができます。私たちも、文字列内のバックスラッシュ、引用符で囲まれた二重引用符を許可することができます。
c_backslash = '\\'
c_dquote = '"'
c_comment = '#'
def chop_comment(line):
# a little state machine with two state varaibles:
in_quote = False # whether we are in a quoted string right now
backslash_escape = False # true if we just saw a backslash
for i, ch in enumerate(line):
if not in_quote and ch == c_comment:
# not in a quote, saw a '#', it's a comment. Chop it and return!
return line[:i]
elif backslash_escape:
# we must have just seen a backslash; reset that flag and continue
backslash_escape = False
elif in_quote and ch == c_backslash:
# we are in a quote and we see a backslash; escape next char
backslash_escape = True
elif ch == c_dquote:
in_quote = not in_quote
return line
私は本当に「初心者」タグの付いた問題で、これが複雑に取得する必要はありませんでしたが、このステート・マシンは、合理的に単純であり、私はそれが面白いことを願っています。
遅くなりましたが、シェル形式(またはPython形式)の扱いの問題です。 #
コメントは非常に一般的なものです。
私はテキスト ファイルを読むたびに、ほぼ毎回何らかのコードを使用してきました。
問題は、引用符またはエスケープされたコメントが適切に処理されないことです。. 。ただし、単純な場合には機能し、簡単です。
for line in whatever:
line = line.split('#',1)[0].strip()
if not line:
continue
# process line
より堅牢なソリューションは次のとおりです。 シュレックス:
import shlex
for line in instream:
lex = shlex.shlex(line)
lex.whitespace = '' # if you want to strip newlines, use '\n'
line = ''.join(list(lex))
if not line:
continue
# process decommented line
この shlex アプローチは、引用符とエスケープを適切に処理するだけでなく、多くの優れた機能 (必要に応じてファイルに他のファイルをソースさせる機能など) を追加します。大きなファイルの速度はテストしていませんが、小さなファイルについては十分に高速です。
各入力行を (空白で) フィールドに分割する一般的なケースはさらに単純です。
import shlex
for line in instream:
fields = shlex.split(line, comments=True)
if not fields:
continue
# process list of fields
これは最短の形態である:
for line in open(filename):
if line.startswith('#'):
continue
# PROCESS LINE HERE
の文字列のstartswith()
メソッドは、文字列はあなたが渡された文字列で始まるでそれを呼び出す場合はTrueを返します。
これはシェルスクリプトのようないくつかの状況では大丈夫ですが、それは2つの問題があります。まず、ファイルを開く方法を指定しません。ファイルを開くためのデフォルトのモードは「バイナリモードでファイルを読み込む」を意味'r'
、です。テキストファイルを期待しているので、'rt'
でそれを開くことをお勧めします。この区別はUNIXライクなオペレーティングシステムには無関係ですが、それはWindows上で(とプリOS XのMac上で)が重要です。
第二の問題は、開いているファイルハンドルです。 open()
機能は、ファイルオブジェクトを返し、あなたが彼らと終わったら、ファイルを閉じるには、良い習慣を考えられています。これを行うには、オブジェクト上close()
メソッドを呼び出します。さて、Pythonの意志の、おそらくのあなたのためにこれを行うには、の最終的に、Pythonオブジェクトでが参照カウントされ、オブジェクトの参照カウントがゼロになったときに、それがいくつかで解放され、かつますオブジェクトが解放された後にポイントPythonはそのデストラクタ(__del__
と呼ばれる特別なメソッド)を呼び出します。 のPythonの実際の参照カウントはプログラムが終了する直前にゼロに低下オブジェクトのデストラクタを呼び出していないの悪い癖を持っている:私はのだろうが言っていることに注意してください。私はそれが急いでだと思う!
シェルスクリプトのような短命のプログラムでは、特にファイルオブジェクトのため、これは重要ではありません。お使いのオペレーティングシステムが自動的にプログラムが終了すると、ハンドルが開いたまま、任意のファイルをクリーンアップします。しかし、あなたは、ファイルを開いて内容を読み取る場合は、明示的に最初のファイルハンドルを閉じずに長い計算を始め、Pythonはあなたの計算中に開いているファイルハンドルを残す可能性があります。そして、それは悪い習慣だ。
このバージョンでは、Pythonのいずれかの2.xバージョンで動作する、および修正私は、上述の問題の両方ます:
f = open(file, 'rt')
for line in f:
if line.startswith('#'):
continue
# PROCESS LINE HERE
f.close()
このは、Pythonの古いバージョンのための最高の一般的な形式です。
の文は、現在考えられている「と」ベスト・プラクティスを使用して、stevehaによって示唆されるように。あなたが2.6以上を使用している場合、あなたはそれをこのように記述する必要があります:
with open(filename, 'rt') as f:
for line in f:
if line.startswith('#'):
continue
# PROCESS LINE HERE
「と」文はあなたのためのファイルハンドルをクリーンアップします。
それは私があなたをここに示したものですので、あなたの質問では、「#で始まる行は」、と述べました。あなたがのオプションの空白ので始まる行をフィルタリングしたいとの後、の「#」の場合、あなたは「#」を探して前に空白を取り除く必要があります。その場合、あなたはこれを変更する必要があります:
if line.startswith('#'):
これに:
if line.lstrip().startswith('#'):
Pythonでは、文字列は不変ですので、これはline
の値を変更しません。 lstrip()
方法は、その先頭の空白が削除されたすべての文字列のコピーを返します。
私は、ジェネレータ関数は、この偉大な仕事をしていることを最近発見しました。私は、などのコメント行、空白行を、スキップする同様の機能を使用しました。
私は
としての私の関数を定義しますdef skip_comments(file):
for line in file:
if not line.strip().startswith('#'):
yield line
、私はちょうどそのように行うことができます。
f = open('testfile')
for line in skip_comments(f):
print line
これは、すべて私のコード全体で再利用可能である、と私は、追加の取り扱い/ログ/などを追加することができます。私は、必要があること。
私は、これは古いスレッドであることを知っているが、これは私ジェネレータ関数であります 私自身の目的のために使用します。それは関係なく、コメントを取り除きませんどこ ラインに表示されるだけでなく、リード/末尾の空白を除去し、 空白行。以下のソーステキスト:
# Comment line 1
# Comment line 2
# host01 # This host commented out.
host02 # This host not commented out.
host03
host04 # Oops! Included leading whitespace in error!
得られます。
host02
host03
host04
デモを含むここに記載されているコード、
def strip_comments(item, *, token='#'):
"""Generator. Strips comments and whitespace from input lines.
This generator strips comments, leading/trailing whitespace, and
blank lines from its input.
Arguments:
item (obj): Object to strip comments from.
token (str, optional): Comment delimiter. Defaults to ``#``.
Yields:
str: Next uncommented non-blank line from ``item`` with
comments and leading/trailing whitespace stripped.
"""
for line in item:
s = line.split(token, 1)[0].strip()
if s:
yield s
if __name__ == '__main__':
HOSTS = """# Comment line 1
# Comment line 2
# host01 # This host commented out.
host02 # This host not commented out.
host03
host04 # Oops! Included leading whitespace in error!""".split('\n')
hosts = strip_comments(HOSTS)
print('\n'.join(h for h in hosts))
通常の使用の場合は、(上記の私の例のように、即ち、ホスト・ファイル)ファイルからのコメントを削除することであろう。この場合は、上記のコードの最後尾をに変更される
if __name__ == '__main__':
with open('hosts.txt', 'r') as f:
hosts = strip_comments(f)
for host in hosts:
print('\'%s\'' % host)
フィルター式のよりコンパクトなバージョンは、このように見ることができます:
for line in (l for l in open(filename) if not l.startswith('#')):
# do something with line
(l for ... )
は、それを反復しながら、ファイルからすべての不要な行を除外しますラッピングイテレータとして、ここで動作する「ジェネレータ式」と呼ばれています。最初のメモリにファイルからすべての行を読み込みますだけにして、それを反復処理を開始します「リスト内包」である正方形のbraketsの[l for ... ]
で同じものと混同しないでください。
時々、あなたはそれより少ない1-lineyと読みやすくしたいかもしれません
lines = open(filename)
lines = (l for l in lines if ... )
# more filters and mappings you might want
for line in lines:
# do something with line
すべてのフィルタは、一回の反復でその場で実行されます。
新しい行やコメントをスキップする正規表現re.compile("^(?:\s+)*#|(?:\s+)")
を使用します。
私が使用する傾向がある。
for line in lines:
if '#' not in line:
#do something
rpartitionを含ん答えは私のupvoteを持っているけれども、それは#前から任意の情報を含めることができるように、これは、行全体が無視されます。