Лучшая реализация регулярных выражений, чем для зацикливания всего файла? - PullRequest
0 голосов
/ 03 сентября 2018

У меня есть файлы, выглядящие так:

#     BJD     K2SC-Flux EAPFlux   Err  Flag Spline
2457217.463564 5848.004 5846.670 6.764 0 0.998291
2457217.483996 6195.018 6193.685 6.781 1 0.998291
2457217.504428 6396.612 6395.278 6.790 0 0.998292
2457217.524861 6220.890 6219.556 6.782 0 0.998292
2457217.545293 5891.856 5890.523 6.766 1 0.998292
2457217.565725 5581.000 5579.667 6.749 1 0.998292
2457217.586158 5230.566 5229.232 6.733 1 0.998292
2457217.606590 4901.128 4899.795 6.718 0 0.998293
2457217.627023 4604.127 4602.793 6.700 0 0.998293

Мне нужно найти и сосчитать строк с флагом = 1 . (5-й столбец.) Вот как я это сделал:

foundlines=[]
c=0
import re
with open('examplefile') as f:
    for index, line in enumerate(f):
        try:
            found = re.findall(r' 1 ', line)[0]
            foundlines.append(index)
            print(line)
            c+=1
        except:
            pass
print(c)

В Shell я бы просто сделал grep " 1 " examplefile | wc -l, что намного короче, чем скрипт Python выше. Скрипт python работает, но меня интересует, есть ли более короткий и более компактный способ выполнения задачи, чем скрипт, описанный выше ? Я предпочитаю краткость Shell, поэтому я хотел бы иметь что-то подобное в Python.

Ответы [ 3 ]

0 голосов
/ 03 сентября 2018

У вас есть данные CSV, вы можете использовать модуль csv:

import csv

with open('your file', 'r', newline='', encoding='utf8') as fp:
    rows = csv.reader(fp, delimiter=' ')

    # generator comprehension
    errors = (row for row in rows if row[4] == '1')

for error in errors:
    print(error)
0 голосов
/ 03 сентября 2018

Кратчайший код

Это очень короткая версия при определенных условиях:

  • Вы просто хотите считать события, как ваш вызов grep
  • Гарантируется, что будет только один " 1 " на линию
  • что " 1 " может встречаться только в нужном столбце
  • Ваш файл легко помещается в память

Обратите внимание, что если эти предварительные условия не выполняются, это может вызвать проблемы с памятью или вернуть ложные срабатывания.

print(open("examplefile").read().count(" 1 "))

Легко и универсально, немного длиннее

Конечно, если вы заинтересованы в том, чтобы потом что-нибудь сделать с этими строками, я рекомендую Pandas:

df = pandas.read_table('test.txt', delimiter=" ",
                       comment="#",
                       names=['BJD', 'K2SC-Flux', 'EAPFlux', 'Err', 'Flag', 'Spline'])

Чтобы получить все строки, где флаг равен 1:

flaggedrows = df[df.Flag == 1]

возвращается:

            BJD  K2SC-Flux   EAPFlux    Err  Flag    Spline
1  2.457217e+06   6195.018  6193.685  6.781     1  0.998291
4  2.457218e+06   5891.856  5890.523  6.766     1  0.998292
5  2.457218e+06   5581.000  5579.667  6.749     1  0.998292
6  2.457218e+06   5230.566  5229.232  6.733     1  0.998292

Для подсчета:

print(len(flaggedrows))

возвращает 4

0 голосов
/ 03 сентября 2018

Ваша реализация оболочки может быть сделана еще короче, grep имеет опцию -c, чтобы получить счетчик, нет необходимости в анонимном канале и wc:

grep -c " 1 " examplefile

Ваш шелл-код просто подсчитывает количество строк, в которых находится шаблон 1, но ваш код Python дополнительно хранит список индексов строк, в которых сопоставляется шаблон.

Только для подсчета количества строк вы можете использовать sum и GeneXP / список понимания, также нет необходимости в Regex; простая строка __contains__ проверка будет выполнена, поскольку строки являются итеративными:

with open('examplefile') as f:
    count = sum(1 for line in f if ' 1 ' in line)
    print(count)  

Если вы также хотите сохранить индексы, вы можете придерживаться своей идеи, заменив только re test на str test:

count = 0
indexes = []
with open('examplefile') as f:
    for idx, line in enumerate(f):
        if ' 1 ' in line:
            count += 1
            indexes.append(idx)

Кроме того, делать голые except почти всегда плохая идея (по крайней мере, вы должны использовать except Exception, чтобы исключить SystemExit, KeyboardInterrupt как исключения), ловите только те исключения, которые, как вы знаете, могут возникнуть.

Кроме того, при разборе структурированных данных вы должны использовать специальный инструмент, например, здесь csv.reader с пробелом в качестве разделителя (line.split(' ') также должно быть сделано в этом случае) и проверка по индексу-4 была бы наиболее безопасной (см. ответ Томалака ). С тестом ' 1 ' in line результаты будут вводить в заблуждение, если любой другой столбец содержит 1.

Учитывая вышеизложенное, вот способ оболочки, использующий awk для сопоставления с 5-м полем:

awk '$5 == "1" {count+=1}; END{print count}' examplefile
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...