Найти - Пользователи
Полная версия: проблемы с парсингом файла (pyparsing)
Начало » Python для новичков » проблемы с парсингом файла (pyparsing)
1
avmartugin
приветствую всех.
у меня проблема с парсингом лог-файлов от онлайн игры fonline.
пример сообщений лога:

16:37:17 • Идет соединение с сервером.
16:40:11 • Вы видите: Деревянная стена.
16:40:15 • Рация 0> ..senjor pisun..
16:48:56 • Человек в кожаной куртке ранен на 36 жизней.
16:48:56 • Человек в кожаной куртке получил ранение в левую руку на 36 жизней.
16:48:52 • Женщина в кожаной куртке была серьезно ранена в пах на 67 жизней. Ее будущие дети под угрозой, так как она падает на землю как куча тряпок.
16:49:56 • Женщина в кожаной куртке критично ранена на 2 жизней без защиты брони, удар опрокидывает женщину на землю.

Мне нужно:
во-первых определить какие из сообщений обычные (не содержат логов боя)
во-втроых определить логи боя и вытащить имена раненых + куда их ударили + на сколько
в третьих определить тех кого критически ранили и опять же куда и на сколько

при беглом анализе видно что обычные сообщеничя отличаются от боевых специальными фразами типа: “ранен на 36 жизней”, “критично ранена на 2 жизней”

я попытался описать грамматику, но при работе моей программы все сообщения попадают в разряд “обычные” (simple). подскажите как исправить ошибку.

import codecs
from pyparsing import *

def crit():
print “crit”

def simple():
print “simple”

#+ combat_aim + combat_dmg
if __name__ == ‘__main__’:
rus_lowercase = u“йцукенгшщзхъфывапролджэячсмитьбю”
rus_uppercase = u“ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ”
eng_lowercase = u“qwertyuiopasdfghjklzxcvbnm”
eng_uppercase = u“QWERTYUIOPASDFGHJKLZXCVBNM”
all_rus_letters = rus_lowercase + rus_uppercase
all_eng_letters = eng_lowercase + eng_uppercase
all_letters = all_rus_letters + all_eng_letters

time = Group(Word(nums) + “:” + Word(nums) + “:” + Word(nums))
time.setName(“time”)
message_delimiter = Suppress(Literal(“•”))
#nick = ZeroOrMore(Word(all_eng_letters + nums)) + ZeroOrMore(Word(all_rus_letters + nums))
nick = OneOrMore(Word(all_rus_letters + nums))
combat_crit = Suppress(Literal(“был серьезно ранен”)) ^ \
Suppress(Literal(“критично ранена”)) ^ \
Suppress(Literal(“выдержал критичное попадание”)) ^ \
Suppress(Literal(“была серьезно ранена”)) ^ \
Suppress(Literal(“выдержала критичное попадание”)) ^ \
Suppress(Literal(“перенесла серьезное ранение”))
combat_aim = Literal(“в голову”) ^ \
Literal(“в левую руку”) ^ \
Literal(“в правую руку”) ^ \
Literal(“в левую ногу”) ^ \
Literal(“в правую ногу”) ^ \
Literal(“в пах”) ^ \
Literal(“в глаза”)
combat_dmg = Suppress(Literal(“на”)) + Word(nums) + Suppress(Literal(“жизней”))
message = Optional(ZeroOrMore(Word(all_rus_letters + nums)))
critshot_record = time + message_delimiter + nick + combat_crit + message
critshot_record.setParseAction(crit)
simple_msg_record = time + message_delimiter + message
simple_msg_record.setParseAction(simple)
record = simple_msg_record ^ critshot_record

fileObj = codecs.open(“D:\Games\FOnline Requiem\messagebox\messbox_2013.01.06_22-09-51.txt”, “r”, “cp1251” )
for line in fileObj.readlines():
print line
rec = record.parseString(line)
print rec

Duck-Pagan
Используйте регулярные выражения.

import re
simple = []
numInString = re.compile('\d+')
if ( numInString.findall(your_line) ):
    simple.append(your_line)

numInString.findall(your_line) - вернет list из цифр в строке your_line.
И нагромождать лишнего не надо.
Duck-Pagan
rus_lowercase = u“йцукенгшщзхъфывапролджэячсмитьбю”
rus_uppercase = u“ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ”
eng_lowercase = u“qwertyuiopasdfghjklzxcvbnm”
eng_uppercase = u“QWERTYUIOPASDFGHJKLZXCVBNM”
Все это и многое другое в вашем коде делается с помощью регулярных выражений намного проще.
А вообще, обычно перед анализом строк их сперва канонизируют: убирают знаки препинания, предлоги\союзы\ - слова до 4х символов(обычно), прописные буквы приводят к виду нижнего регистра.
А уже после этого производят манипуляции с текстом: поиск, сортировка и тд.
avmartugin
ники регистрозависимые
знаки препинания нужнеы чтобы сразу отсеять ненужную информацию (после запятой инфа не нужна)
надо просто описать грамматику, но у меня этого сделать не получается… не вижу своей ошибки
на более простых текстах описать грамматику получаелось без особого дебага. но тут получается что боевая грамматика поглощается простой грамматикой (включает в себя полностью). либо такие тексты не получится распарсить этой библиотекой в принципе, либо я не знаю какой-то фишки которая сделает боевую грамматику более приоритетной для парсера
py.user.next
avmartugin
во-первых определить какие из сообщений обычные (не содержат логов боя)
во-втроых определить логи боя и вытащить имена раненых + куда их ударили + на сколько
в третьих определить тех кого критически ранили и опять же куда и на сколько
если есть слово, начинающееся с “ранен”, то это строка боя
составить “грамматику строки боя”, которая включает “грамматику имени”, “грамматику места”, “грамматику урона”

avmartugin
16:48:56 • Человек в кожаной куртке ранен на 36 жизней.
это куда ранен ?

пиши грамматику словами, начиная с нетерминалов, переходя к терминалам
грамматику можно рисовать, чтобы проверить, правильная ли она
avmartugin
py.user.next
ну я вот это и попытался сделать, но не получилось.
как сделать грамматику ника чтобы она включала пробел? ник может состоять из англ. и русских букв, чисел и пробелов
py.user.next
давай набор ников, которые принадлежат и которые не принадлежат грамматике
avmartugin
Человек в кожаной куртке
Сучка
Mechan
DeaDNick
Frost Nova
mr.tesla
freeman1


вот такие могут быть ники
т.е. любые буквы латиницы + русские, также точка и пробел
в общем в сообщении боя для критавсе что после игрового времени и знака ( • ) и до слов:
“был серьезно ранен”
“критично ранена”
“выдержал критичное попадание”
“была серьезно ранена”
“выдержала критичное попадание”
“перенесла серьезное ранение” является ником
py.user.next
<сообщение боя> ::= <юнит><удар>

<юнит> ::= <слово>{<разделитель><слово>}

<удар> ::= <степень урона><жизни> | <степень урона><место урона><жизни>

<степень урона> ::= "ранен" | "получил ранение" | "критично ранен"

<место урона> ::= "в левую руку" | "в пах"

<жизни> ::= "на" <число> "жизней"

дальше <слово> и <разделитель> можно задавать по-разному, а <число> делаешь отдельно и присоединяешь к основной грамматике
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB