Python: как игнорировать строки #comment при чтении в файле
в Python я только что прочитал строку из текстового файла, и я хотел бы знать, как кодировать, чтобы игнорировать комментарии с хэшем # в начале строки.
Я думаю, что это должно быть что-то вроде этого:
for
if line !contain #
then ...process line
else end for loop
но я новичок в Python и я не знаю синтаксис
9 ответов
можно использовать startswith ()
например
for line in open("file"):
li=line.strip()
if not li.startswith("#"):
print line.rstrip()
я советую вам не игнорировать всю строку, когда вы видите #
символ; просто игнорируйте остальную часть строки. Вы можете сделать это легко с помощью функции string method с именем partition
:
with open("filename") as f:
for line in f:
line = line.partition('#')[0]
line = line.rstrip()
# ... do something with line ...
partition
возвращает кортеж: все до строки раздела, строка раздела и все после строки раздела. Итак, индексируя с [0]
мы берем только часть перед строкой раздела.
изменить:
Если вы используете версию Python что нет partition()
, вот код, который вы можете использовать:
with open("filename") as f:
for line in f:
line = line.split('#', 1)[0]
line = line.rstrip()
# ... do something with line ...
это разбивает строку на символ"#", а затем сохраняет все до разделения. The
это в кратчайшей форме:
for line in open(filename):
if line.startswith('#'):
continue
# PROCESS LINE HERE
на startswith()
метод в строке возвращает True, если строка, которую вы вызываете, начинается со строки, которую вы передали.
хотя это нормально в некоторых обстоятельствах, таких как сценарии оболочки, у него есть две проблемы. Во-первых, он не указывает, как открыть файл. По умолчанию файл открывается в режиме 'r'
, что означает чтение файла в двоичном режиме. Поскольку вы ожидаете текстовый файл лучше открыть его с 'rt'
. Хотя это различие не имеет значения для UNIX-подобных операционных систем, оно важно для Windows (и для Mac до OS X).
вторая проблема-дескриптор открытого файла. The open()
функция возвращает объект file, и считается хорошей практикой закрывать файлы, когда вы закончите с ними. Для этого вызовите close()
метод на объекте. Теперь, Python будет наверное сделай это для себя, в конце концов; в Python объекты reference-подсчитано, и когда счетчик ссылок объекта идет к нулю, он освобождается, и в какой-то момент после освобождения объекта Python вызовет его деструктор (специальный метод под названием __del__
). Обратите внимание, что я сказал вероятно: Python имеет плохую привычку фактически не вызывать деструктор на объектах, количество ссылок которых падает до нуля незадолго до завершения программы. Я думаю, он торопится!
для краткосрочных программ, таких как сценарии оболочки, и особенно для файловые объекты, это не имеет значения. Ваша операционная система автоматически очистит все дескрипторы файлов, оставленные открытыми после завершения программы. Но если вы открыли файл, прочитали содержимое, а затем начали долгое вычисление без явного закрытия дескриптора файла, Python, вероятно, оставит дескриптор файла открытым во время вашего вычисления. И это плохая практика.
эта версия будет работать в любом 2.x версия Python и исправляет обе проблемы, которые я обсуждал сверху:
f = open(file, 'rt')
for line in f:
if line.startswith('#'):
continue
# PROCESS LINE HERE
f.close()
это лучшая общая форма для более старых версий Python.
как предложил стивеха, использование заявления " с " теперь считается лучшей практикой. Если вы используете 2.6 или выше, вы должны написать так:
with open(filename, 'rt') as f:
for line in f:
if line.startswith('#'):
continue
# PROCESS LINE HERE
оператор "with" очистит дескриптор файла для вас.
в вашем вопросе вы сказали " строки, которые начинаются с#", так что это то, что я показал вам здесь. Если вы хотите отфильтровать строки, которые начинаются с необязательный пробел и затем a'#', вы должны очистить пробелы, прежде чем искать"#". В этом случае, вы должны изменить это:
if line.startswith('#'):
для этого:
if line.lstrip().startswith('#'):
в Python строки неизменяемы, поэтому это не изменяет значение line
. The lstrip()
метод возвращает копию строки с все пробелы удалены.
Я прихожу в это поздно, но проблема обработки стиля оболочки (или стиля python) #
комментарии очень распространены.
Я использую некоторые код почти каждый раз, когда я читаю текстовый файл.
проблема в том, что он не обрабатывает процитированные или экранированные комментарии должным образом. Но это работает для простых случаев и легко.
for line in whatever:
line = line.split('#',1)[0].strip()
if not line:
continue
# process line
более надежным решением является использование shlex:
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
недавно я обнаружил, что функция генератора отлично справляется с этим. Я использовал аналогичные функции для пропуска строк комментариев, пустых строк и т. д.
Я определяю свою функцию как
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
Это многоразово во всем моем коде,и я могу добавить любую дополнительную обработку / ведение журнала / и т. д. это мне нужно.
более компактная версия фильтрующего выражения также может выглядеть следующим образом:
for line in (l for l in open(filename) if not l.startswith('#')):
# do something with line
(l for ... )
называется "выражение генератора", которое действует здесь как итератор обертывания, который будет отфильтровывать все ненужные строки из файла при итерации по нему. Не путайте его с тем же самым в квадратных скобках [l for ... ]
это "понимание списка", которое сначала прочитает все строки из файла в память и только затем начнет итерацию по нему.
иногда возможно, вы захотите, чтобы он был менее однострочным и более читаемым:
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
все фильтры будут выполняться на лету за одну итерацию.
Я знаю, что это старый нить, но это функция генератора, которую я использовать в своих целях. Он раздевает комментарии независимо от того, где они появляются в строке, а также зачищают начальные / конечные пробелы и пустая строка. Следующий исходный текст:
# 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 non-blank line from ``item`` with comments and
leading/trailing whitespace removed.
"""
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))
обычным вариантом использования будет удаление комментариев из файла (т. е. файла hosts, как в my пример выше). Если это так, то хвостовая часть вышеуказанного кода будет изменена на:
if __name__ == '__main__':
with open('hosts.txt', 'r') as f:
hosts = strip_comments(f)
for host in hosts:
print('\'%s\'' % host)
Я предпочитаю использовать
for line in lines:
if '#' not in line:
#do something
Это будет игнорировать всю строку, хотя ответ, который включает rpartition, имеет мой upvote, поскольку он может включать любую информацию до #