Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Python: Общие вопросы > разбить строку на токены


Автор: volatile 22.2.2011, 01:22
Python, изучаю недавно (всего несколько дней)
Хочу написать небольшой парсер С++ файлов. *.cpp; *.h
Нужно разбить строку на токены.
Код

fin = open('main.cpp')
for line in fin:
     # вот здесь line надо разбить на токены


упрощенный вариант: пока идут символы A-Z;a-z;0-9;_ считается одним токеном
как встретился другой символ, значит токен кончился.
как это можно организовать.
пока нашел только line.split(...), но там можно только один символ.

Автор: spSerg 22.2.2011, 10:03
Вообще-то есть штатная батарейка: http://docs.python.org/library/tokenize.html
Только боюсь, для cpp она не очень.

Автор: volatile 22.2.2011, 23:09
spSerg, спасибо. Но этот действительно похоже только для исходников самого пайтона.

Как я понял, нужно писать посимвольный ввод.
Думал на пайтоне можно сделать проще...

Автор: spSerg 23.2.2011, 16:08
Еще можно попробовать что-то помощнее.
Например, ANTLR генератор парсеров:
http://www.antlr.org/

а тут сама грамматика C++:
http://www.antlr.org/grammar/cpp

Только это решение не на чистом пайтоне получится.

Тут либо большие решения, либо можно для отдельного подмножества случаев даже регулярками обойтись. 
Все зависит от задачи. Выбор за разработчиком. Удачи.

Автор: volatile 24.2.2011, 01:18
spSerg, спасибо за ссылки.
Но, вероятно, я не совсем корректно сформулировал вопрос.
Упростим задачу. Отвлечемся от токенов и с++.

Чистый пайтон.
Допустим есть строка "abc,def;gty-klp"
Как наиболее простым способом ее разбить на кортеж ("abc", "def", "gty", "klp") ?
Символы разделители допустим могут быть такие: "<=>!&|^+-*/%:;(),~{}[]" 




Автор: av0000 24.2.2011, 10:57
В такой постановке - элементарно smile

Код

import re

s = "abc,def;gty-klp"
r = re.compile(r"<=>!&|^+\-*/%:;(),~{}\[\]+") # экранировать минимум знак "минус" и закрывающую квадратную скобку
ret = r.split(s) # тут будут результаты с пустыми строками вместо разделителей
# надо именно кортеж - 
ret2 = tuple([x for x in ret if x]) # а тут мы эти пустые строки "тупо" выкинем :)

print ret2



Автор: volatile 24.2.2011, 23:49
av0000, в том виде как вы привели вообще не работает
методом тыка удалось установить что еще '+' надо экранировать.
В итоге программку удалось запустить в таком виде:
Код
# -*- coding: windows-1251 -*-
import re
s = "abc,def;gty-klp"
r = re.compile(r"<=>!&|^\+\-/%:;(),~{}\[\]+")
ret = r.split(s) # тут будут результаты с пустыми строками вместо разделителей
ret2 = tuple([x for x in ret if x]) # а тут мы эти пустые строки "тупо" выкинем :)
print ret2

Но она ничего не делает.
выход:
Цитата

('abc,def;gty-klp',)

то есть как была строка так и осталась.
дальше разбираться не стал...

Добавлено через 10 минут и 9 секунд
а, re это - regular expressions?

в любом случае спасибо за наводку, av0000

Автор: spSerg 25.2.2011, 09:16
Ну не проверил человек. С кем не бывает smile 
В регулярке квадратные скобки забыл.
Код

import re
s = "abc,def;gty-klp"
r = re.compile(r"[<=>!&|^\+\-/%:;(),~{}\[\]]+")
ret = r.split(s) #здесь получится список слов

Автор: av0000 25.2.2011, 11:42
Угу...

Перенабивал, поленившись копировать из консоли, — так не только квадратные скобки, а ещё и "лишнюю" группу "(.*?)" которая давала пустые строки (оттуда и коммент про пустые строки) забыл, вернее "удачно" убрал" ;)

Изначальная строчка была print re.split(r"(*.?)[<=>!&|^+\-*/%:;()~{}[\],]+",s)

В качестве компенсации офф-топика хочу поделиться наблюдением:
Неспешно делаю очередную версию напоминалки об обновлениях на СамИздат-е с парсингом страничек и местами автоматическим конвертированием в .fb2... Так вот, тесты показали, что регекспы в 3-8 раз медленнее аналогичной реализации "руками" через startswith/find/endswith и т.п. Поэтому, если важна скорость обработки - стОит очень внимательно подумать что окажется выгоднее - медленный, "осмысленный" регэксп или 5-30 строк "ручного" кода. Для примера - вот те регекспы. До всякой оптимизации - попробовал "руками" и плюнул.. 
Код

# ================ чистка текста ================
# сравнение скорости...
# ** 3x медленнее
RE_FONT1 = re.compile(ur'<font\s+color="?\#\d{3,6}"?\s*>?|<font\s+color="?\w+"?\s*>|</font>', re.I|re.U|re.S|re.M)
# ** 6x
#RE_RM1 = re.compile(ur"(<[/]?div.*?>)|(<[/]?body.*?>)|(<[/]?html.*?>)|(<[/]?xxx.*?>)|(<i></i>)|(<u></u>)|(<b></b>)", re.I | re.S | re.M | re.U)
# ** 1x (0.21s x 700Kb)
#RE_DD = re.compile(ur"(<dd>)(?:&nbsp;)*\s*(.*?)($\s*^(?=<))", re.I|re.M|re.S|re.U)
# ** 8x
#RE_ONOFF = re.compile(ur"<(\w+)>(.*?)</\1><\1>", re.I|re.M|re.U|re.S)
# ======================================


ЗЫ: Да и в сторону tokenize посмотреть не мешает... для более сложной грамматики, нежели разбивка по разделителям может оказаться проще, а то и быстрее...

Автор: volatile 25.2.2011, 23:11
spSerg, 
av0000, 

Большое спасибо ребята!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)