Разбор текстового файла с Python - PullRequest
0 голосов
/ 17 февраля 2019

Я должен проанализировать документ в текстовом файле, который находится в таких столбцах, как этот:

  Sun       -    S    exst    sun      s    [STA|X|Away]
  Moon      -    M    exst    moon     s    [SAT|X|Not away]
  Mars      +    M    exst    mars     p    [PLAN|X|Away]
  Venus     +    V    exst    venus    p    [PLAN|X|Away]
  Uranus    -    U    exst    uranus   u    [UNK|X|Away], [SAT|X|Away], [BLA|X|Away]
  Mercury   +    M    exst    mercury  u    [UNK|X|Away], [PLAN|X|Away]

В конце он должен создать новый файл, который будет выглядеть следующим образом:

Sun        -     exst    ['STA']
Moon       -     exst    ['SAT']
Mars       +     exst    ['PLAN']
Venus      +     exst    ['PLAN']
Uranus     -     exst    ['UNK', 'SAT', 'BLA']
Mercury    +     exst    ['UNK', 'PLAN']

Это упражнение имеет целью научиться использовать регулярные выражения.

У меня есть поиск в сети информации о том, как анализировать документы, но я не могу найти ни одного хорошего, которое бы хорошо это объясняло или служило.меня, особенно, кстати, моя информация в начале (в столбцах).Если бы вы могли помочь мне узнать, каким должен быть код, объясните мне синтаксис синтаксического анализа или дайте мне ссылки на информацию, которая могла бы объяснить это мне, я буду очень рад.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Использование регулярных выражений кажется немного неловким, учитывая, что ввод находится в фиксированном формате записи;тем не менее, решение ниже использует регулярные выражения для сохранения преобразований.Обратите внимание, что процесс состоит из двух этапов, так как я не верю, что Python обрабатывает группы групп, что необходимо для идентификации первых элементов всех массивов в последнем разделе записи.

Используйте record_re для идентификациикаждое поле в строке ввода.Затем используйте первое регулярное выражение, чтобы получить первый элемент каждого списка, найденный в последнем поле строки ввода.

import sys
import re


class FixedTransform(object):
    fields = [
            "",
            "(?P<CELESTIAL_BODY>[^\s]+)",
            "(?P<SIGN>[-+])",
            "(?P<LETTER>.)",
            "(?P<EXST>exst)",
            "(?P<LOWER>[^\s]+)",
            "(?P<TYPE>[^\s])",
            "(?P<LIST>\[.*\])"
    ]

    record_re = re.compile(r"\s+".join(fields))
    firsts = r"\[([^\|]+)"

    def __init__(self, filein, fileout=sys.stdout):
        self.filein = filein
        self.fileout = fileout

    def raw_records(self):
        with open(self.filein, "r") as fin:
            for line in fin:
                yield line[:-1]

    def parsed_records(self):
        for line in self.raw_records():
            groups = self.record_re.match(line)
            if groups is not None:
                fields = groups.groupdict()
                last_group = fields.get("LIST")
                firstels = re.findall(self.firsts, last_group)
                fields["LIST"] = firstels
                yield fields

    def transform(self):
        fields_out = [
                "CELESTIAL_BODY",
                "SIGN",
                "EXST",
                "LIST"
        ]
        for doc in self.parsed_records():
            xform = {f: doc.get(f) for f in fields_out}
            yield xform

    def format_out(self, doc):
        return "{CELESTIAL_BODY:11s}{SIGN:6s}{EXST:8s}{LIST}".format(**doc)


if __name__ == "__main__":
    ft = FixedTransform("infile.txt")
    for doc in ft.transform():
        print(ft.format_out(doc))

Я разбил регулярное выражение на отдельные компоненты для удобства чтения и тестирования.Это позволило сохранить выражение в управляемом формате и упростить его обновление.Поскольку поля разделены пробелами, я просто скомбинировал отдельные регулярные выражения, используя метод str.join Python, перед тем как скомпилировать выражение.

выполнение кода для ввода, представленного в вашем вопросе, дает:

Sun        -     exst    ['STA']
Moon       -     exst    ['SAT']
Mars       +     exst    ['PLAN']
Venus      +     exst    ['PLAN']
Uranus     -     exst    ['UNK', 'SAT', 'BLA']
Mercury    +     exst    ['UNK', 'PLAN']
0 голосов
/ 17 февраля 2019

вы бы использовали библиотеку pandas, это простые в использовании структуры данных и инструменты анализа данных для Python.

установка:

на Python 2

pip install pandas

на python 3

pip3 install pandas

код: этот код будет считывать определенные столбцы из вашего файла в кадр данных pandas, а затем применять регулярное выражение к последнему столбцу, а затемсохраните данные в новый файл.

# importing pandas
import pandas as pd

# import re library
import re

# use read_csv method to read your data file
# delimiter='\t' used if your file is tsp (tsv separated values)
# or delim_whitespace=True if your file use multiple white spaces
# or delimiter=r"[ ]{2,}" to use only more than 2 spaces as your last column uses space inside its value, actually we use regex here.
# usecols=[0,1,3,6] to load those columns only
# optionaly give names to your columns if there is no header in your file names=['colA', 'colB')
df = pd.read_csv('yourfile.txt', delimiter=r"[ ]{2,}", usecols=[0,1,3,6], names=['colA', 'colB', 'colC', 'colD'])


# we make our regex pattern here. thanks to @Kristian
pattern = r"\[([^\|]+)"

# define a simple regex function that will called for every value in your last column. or we could supply lambda to pandas apple method.


def regex_func(value):
    return re.findall(pattern, value)


# apply regex to last column values
df['colD'] = df['colD'].apply(regex_func)

# print the results
print(df)

# save your dataframe to new file
# index=false to save df without row names
# header=False to save df without columns names
# sep='\t' to make it tab separated values
df.to_csv('yournewfile.csv', sep='\t', index=False, header=False)

, как вы видите с пандами, вы можете использовать только несколько строк кода, без циклов и т. д., чистыми и простыми в обслуживании.

test-drive код:

я копирую и вставляю содержимое выходного файла:

Sun -   exst    ['STA']
Moon    -   exst    ['SAT']
Mars    +   exst    ['PLAN']
Venus   +   exst    ['PLAN']
Uranus  -   exst    ['UNK', 'SAT', 'BLA']
Mercury +   exst    ['UNK', 'PLAN']

ссылки:

officialpandas docs:

http://pandas.pydata.org/pandas-docs/stable/

pandas Tutorials:

https://pandas.pydata.org/pandas-docs/stable/getting_started/tutorials.html

https://www.datacamp.com/community/tutorials/pandas-tutorial-dataframe-python

https://www.tutorialspoint.com/python_pandas

обновление:

я заметил, что ваш файл отсутствует (значения, разделенные табуляцией).он использует несколько пробелов.Сначала я подумал, что могу использовать delim_whitespace = True в методе read_csv

df = pd.read_csv('yourfile.txt', delim_whitespace=True, usecols=[0,1,3,6], names=['colA', 'colB', 'colC', 'colD')

Это помогает, когда у вас есть несколько пробелов в качестве разделителя.

, но в качестве последнего столбцаиспользуйте один пробел в своих значениях, и в результате вы получите неожиданные результаты, поэтому правильный способ для правильного разбора столбцов, включенных в последний столбец, заключается в использовании регулярного выражения с разделителем arg, delimiter = r "[] {2,}"

df = pd.read_csv('yourfile.txt', delimiter=r"[ ]{2,}", usecols=[0,1,3,6], names=['colA', 'colB', 'colC', 'colD'])

update2

Я обновляю код в своем ответе, чтобы показать, как легко применять регулярные выражения к столбцу при использовании pandas

простая одна строкабудет применять функцию к каждому значению из вашего последнего столбца

df['colD'] = df['colD'].apply(regex_func)

Я включил в свой код функцию регулярного выражения для удобства чтения, но это также может быть простой лямбда-вызов, подобный этому

df['colD'] = df['colD'].apply(lambda value: re.findall(r"\[([^\|]+)", value))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...