Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 24, 2017 12:41:44

appolo440
Зарегистрирован: 2017-02-24
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Друзья, я только начинаю изучать язык, у меня такой вопрос к опытным людям.

Есть файл, примерно вот с таким содержимым:
<code=“524426745”>
<id=1>
<id=2>
</code=“524426745”>

<code=“524426442”>
<id=1>
<id=2>
</code=“524422442”>

Задача такова, надо найти начало блока по коду то есть: <code=“524426745”>, и читать строки в переменную или в файл до тех пор пока не дойдем до </code=“524426745”>

Я набросал такой код:

 f = open('russianpost.log', 'r')
for line in f.xreadlines():
	if '524426745' in line:
		print line	
f.close()

Это выводит мне соответственно 2 строки, потому что код находит вхождение. Каким образом мне добавить к этому ещё все то, что находиться внутри блока?

Что бы при поиске вхождения он выводил мне весь блок:

<code=“524426745”>
<id=1>
<id=2>
</code=“524426745”>

Спасибо заранее. Наверное надо смотреть в сторону while?

Офлайн

#2 Фев. 24, 2017 13:57:19

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9726
Репутация: +  843  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

  
>>> import re
>>> 
>>> text = """
... 
... <code="524426745">
... <id=1>
... <id=2>
... </code="524426745">
... 
... <code="524426442">
... <id=3>
... <id=4>
... </code="524422442">
... 
... <code="524426443">
... <id=5>
... <id=6>
... </code="524422443">
... 
... """
>>> 
>>> def split_records(s):
...     pat = r'<code.*?</code.*?>'
...     out = re.findall(pat, s, re.DOTALL)
...     return out
... 
>>> def parse_record(s):
...     pat = r'<code="(.*)">(.*)</code.*>'
...     match = re.search(pat, s, re.DOTALL)
...     if match is not None:
...         number = match.group(1)
...         content = parse_content(match.group(2))
...         return (number, content)
...     else:
...         return None
... 
>>> def parse_content(s):
...     pat = r'<id=(.*)>'
...     out = tuple(re.findall(pat, s))
...     return out
... 
>>> records = split_records(text)
>>> records
['<code="524426745">\n<id=1>\n<id=2>\n</code="524426745">', '<code="524426442">\n<id=3>\n<id=4>\n</code="524422442">', '<code="524426443">\n<id=5>\n<id=6>\n</code="524422443">']
>>> 
>>> out = list(map(parse_record, records))
>>> out
[('524426745', ('1', '2')), ('524426442', ('3', '4')), ('524426443', ('5', '6'))]
>>>

25 Feb 2017 12:05:40 Edit
Дописал дальнейший разбор.



Отредактировано py.user.next (Фев. 25, 2017 03:06:01)

Офлайн

#3 Фев. 24, 2017 16:34:31

appolo440
Зарегистрирован: 2017-02-24
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Честно сказать я не совсем понял решение. Если честно. Как я это вижу? Открывается файл, ищем весь текст до первого вхождения (<code=“524426745”>), находим, значит выводим строку, раз строка найдена, выводим все остальные строки до тех пор, пока не встретим второе вхождение (</code=“524426745”>) .

Я думал искать по следующему, первое вхождение (524426745), потом все строки, второе вхождение (</code).

Вот как-то так…

Офлайн

#4 Фев. 24, 2017 17:03:05

Romissevd
От: Счастье
Зарегистрирован: 2015-03-01
Сообщения: 533
Репутация: +  76  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Вот, наверное, то, как видите Вы

 with open('2.txt', 'r') as f:
    start = False
    for line in f:
        if '<code="524426745">' in line:
            start = True
        if start:
            print(line)
        if '</code="524426745">' in line:
            start = False
Но Вам уже предложил универсальное решение py.user.next, а то что я написал - это ГОВНОКОД.

Отредактировано Romissevd (Фев. 24, 2017 17:03:29)

Офлайн

#5 Фев. 24, 2017 17:10:58

appolo440
Зарегистрирован: 2017-02-24
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Да! Это именно то, что мне было нужно… теперь буду разбираться. А почему вы считаете что это говнокод? Ведь это работает. Может быть с точки зрения “чистого” программирования это и выглядит нагромождением, но ведь работает . При том делает как раз то, что мне было нужно…

Офлайн

#6 Фев. 25, 2017 03:24:02

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9726
Репутация: +  843  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

appolo440
Честно сказать я не совсем понял решение. Если честно. Как я это вижу? Открывается файл, ищем весь текст до первого вхождения (<code=“524426745”>), находим, значит выводим строку, раз строка найдена, выводим все остальные строки до тех пор, пока не встретим второе вхождение (</code=“524426745”>) .
Ты когда файл прочитаешь через f.read(), получишь текст весь, который подашь в функцию, которая разделяет его на записи. И потом, когда уже разделишь его на записи, ты возьмёшь первую из них.

Там я дописал разбор, теперь записи сразу транслируются в кортежи.

appolo440
Может быть с точки зрения “чистого” программирования это и выглядит нагромождением, но ведь работает .
У Romissevd оно берёт только определённую запись (с определённым номером) и больше ничего не делает с ней. Если тебе понадобится запись с другим номером, то этот код ты уже не применишь, потому что в нём номер зашит (надо менять код). Если код надо менять, то он фиговым считается, так как хороший код параметризован - ты просто меняешь вводный параметр и код без каких-либо изменений применим к другим записям. Чем больше код параметризован, тем он лучше. В данном случае код должен быть параметризован ещё и по источнику данных. Но у него в код зашито ещё и то, что данные берутся только из файла. Значит, если они придут по сети (через соединение) или по почте, то ты не сможешь эти данные сразу подать в код, потому что он требует именно файл, сначала ты должен будешь сохранять данные на диск, а потом этот файл подавать, но данные на диск может быть запрещено сохранять или на нём может закончиться место. В хорошем коде данные принято передавать прямо из оперативной памяти (она быстрее работает, чем диски, и меньше изнашивается). Ну, и самая главная параметризация, которая у него отсутствует, - это номер записи по счёту. Он не может выбрать третью запись из пяти, например, и с ней работать, потому что он вообще их не считает. Он не может выбрать 3, 10 и 115 записи, потому что сами записи в его потоке не разделяются.

А в моём коде косяк только в том, что текст нужно целиком подавать, а он может быть огромным (на гигабайты). Но это можно поменять хотя бы потом, и то, если это вообще понадобится. Там легко поменять это.

Ну, и из дописанного видно, что у меня подаётся просто череда записей, а на выходе получается череда кортежей, в которые уже всё извлечено из этих записей. То есть с этим можно работать уже, брать значения, менять что-то и обратно сформировывать и выводить.

Было вот так:
<code="524426745">
<id=1>
<id=2>
</code="524426745">

Стало вот так:
('524426745', ('1', '2'))



Отредактировано py.user.next (Фев. 26, 2017 01:55:23)

Офлайн

#7 Фев. 25, 2017 11:44:51

appolo440
Зарегистрирован: 2017-02-24
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Спасибо всем друзья!
С вашей помощью привел свой код до следующего состояния:
В файл in.log записываются коды вхождений.

Вначале файла задаю переменные и далее отрабатываю:

 in_log = 'in.log'
out_log = 'out.log'
def parse_line(input_file, start_string, end_string):
        start_parse = False
        f = open (input_file, 'r')
        for line in f.xreadlines():
                if start_string in line:
                        start_parse = True
                if start_parse:
                        print line,
                if end_string in line:
                        start_parse = False
        f.close()
def search_line():
        f = open (in_log, 'r')
        for lines in f.xreadlines():
                line = lines.split()
                parse_line(out_log, line[0], '</')
        f.close()
search_line()

Спасибо всем за помощь!

Офлайн

#8 Фев. 25, 2017 12:28:47

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

appolo440
привел свой код до следующего состояния:
:) Добавлю свою ложку дегтя.
Вот не претендуя на полную корректность код парсера-фильтра:

a.xml:
<code=“524426745”>
<id=1>
<id=2>
</code=“524426745”>
<code=“524426748”>
<id=1>
<id=2>
</code=“524426748”>
<code=“524426749”>
<id=1>
<id=2>
<id=22>
</code=“524426749”>

 import re
def cvt(fnd):
    if fnd.group(1)=="code":
        return fnd.group(2) +" :\n"
    if fnd.group(1)=="id":
        return "  - " + fnd.group(2)
    return ""
with open("a.xml","r") as f_in, open("a.yaml","w") as f_out:
    for i in f_in:
        f_out.write(re.sub("<(.+)=(.+)>",cvt,i))

После этого данные читаются так:
 import yaml
with open("a.yaml","r") as f:
    d=yaml.load(f)

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

При этом вы не только считаете данные. Вы получите нормализованную форму хранения. При случае вы сможете настучать по башке тому кто данные поставляет и показать что именно вам нужно и если он все поправит то можно будет вообще выкинуть все эти наши коды и упростить систему.



Отредактировано doza_and (Фев. 25, 2017 12:32:17)

Офлайн

#9 Фев. 25, 2017 12:38:55

appolo440
Зарегистрирован: 2017-02-24
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

Дело в том, что это не .xml формат. Я привел это исключительно ради примера, в файле в котором будет производится поиск куча всего, это stdout от java приложения, туда пишется все что только можно, включая нужную мне информацию. Но спасибо вам за время и внимание! )

Офлайн

#10 Фев. 25, 2017 15:02:01

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Поиск вхождения и чтение блока

appolo440
Дело в том, что это не .xml формат.
А я и не предполагал что это xml, никакие xml парсеры не использовал. Как раз когда в файле куча непотребного мусора фильтры проще всего и писать. Зачастую вы при этом разбираете пару вам нужных конструкций из сотен, поэтому код сильно сокращается. Но самый лучший способ это залезть в java код и изменить сохранение так чтобы не было проблем с чтением.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version