разбить строку на токены

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

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


упрощенный вариант: пока идут символы A-Z;a-z;0-9;_ считается одним токеном
как встретился другой символ, значит токен кончился.
как это можно организовать.
пока нашел только line.split(...), но там можно только один символ.
Kommentare (9)
ava
spSerg | 22.02.2011, 10:03 #
Вообще-то есть штатная батарейка: http://docs.python.org/library/tokenize.html
Только боюсь, для cpp она не очень.
ava
volatile | 22.02.2011, 23:09 #
spSerg, спасибо. Но этот действительно похоже только для исходников самого пайтона.

Как я понял, нужно писать посимвольный ввод.
Думал на пайтоне можно сделать проще...
ava
spSerg | 23.02.2011, 16:08 #
Еще можно попробовать что-то помощнее.
Например, ANTLR генератор парсеров:
http://www.antlr.org/

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

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

Тут либо большие решения, либо можно для отдельного подмножества случаев даже регулярками обойтись.
Все зависит от задачи. Выбор за разработчиком. Удачи.
ava
volatile | 24.02.2011, 01:18 #
spSerg, спасибо за ссылки.
Но, вероятно, я не совсем корректно сформулировал вопрос.
Упростим задачу. Отвлечемся от токенов и с++.

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



ava
av0000 | 24.02.2011, 10:57 #
В такой постановке - элементарно :)


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


ava
volatile | 24.02.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',)


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

später ergänzt:
а, re это - regular expressions?

в любом случае спасибо за наводку, av0000
ava
spSerg | 25.02.2011, 09:16 #
Ну не проверил человек. С кем не бывает smile
В регулярке квадратные скобки забыл.

import re
s = "abc,def;gty-klp"
r = re.compile(r"[<=>!&|^\+\-/%:;(),~{}\[\]]+")
ret = r.split(s) #здесь получится список слов
ava
av0000 | 25.02.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 посмотреть не мешает... для более сложной грамматики, нежели разбивка по разделителям может оказаться проще, а то и быстрее...
ava
volatile | 25.02.2011, 23:11 #
spSerg,
av0000,

Большое спасибо ребята!
Registrieren Sie sich oder melden Sie sich an, um schreiben zu können.
Unternehmen des Tages
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Mitwirkende
advanced
Absenden