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)

использовать regex re.compile("^(?:\s+)*#|(?:\s+)") пропустить новые строки и комментарии.


Я предпочитаю использовать

for line  in lines:
    if '#' not in line:
        #do something

Это будет игнорировать всю строку, хотя ответ, который включает rpartition, имеет мой upvote, поскольку он может включать любую информацию до #