Бандаж сопряжения ({}[]()<>) очистки/ускорение


Это работает, как ожидалось, за исключением скорость + мне нужно, чтобы сделать его более читабельным и коротким, если это возможно, я, наверное, много вещей мне не нужно :).

Редактировать это работает сейчас

charset = dict(opening='{[(<',\
    closing='}])>',\
    string = ('"', "'"),\
    comment=(('<!--', '-->'), ('"""', '"""'), ('#', '\n')))

allowed = ''.join([x[0][0] + x[1][0] for x in charset['comment']])
allowed += ''.join(charset['string'])
allowed += charset['opening']
allowed += charset['closing']

def brace_check(text):
    o = []
    c = []
    notr = []
    found = []
    busy = False
    last_pos = None
    for i in xrange(len(text)):
        ch = text[i]
        if not busy:
            cont = True
            for comment in charset['comment']:
                if ch == comment[0][0]:
                    como = text[i:len(comment[0])]
                    if como == comment[0]:
                        busy = comment[1]
                        if ch in charset['opening']:
                            last_pos = i
                        cont = False
                        break
            if cont:
                if ch in charset['string']:
                    busy = ch
                elif ch in charset['opening']:
                    o.append((ch, i))
                elif  ch in charset['closing']:
                    c.append((ch, i))
        else:
            if ch == busy[0]:
                if len(busy) == 1:
                    comc = ch
                else:
                    comc = text[i:i + len(busy)]
                if comc == busy:
                    if last_pos is not None:
                        if busy[-1] in charset['closing']:
                            found.append((last_pos, i))
                        last_pos = None
                        text = text[:i] + '\n' * len(comc) +\
                            text[i + len(comc):]
                    busy = not busy
            elif busy in charset['string']:
                if ch == '\n':
                    busy = not busy
    for t, e in reversed(o):
        try:
            n = next((b, v) for b, v in c\
                if b == charset['closing'][\
                    charset['opening'].find(t)] and v > e)
            c.remove(n)
            n = n[1]
            if found != []:
                if e < found[-1][0] and n > found[-1][0] and n < found[-1][1]\
                or e < found[-1][1] and n > found[-1][1] and e > found[-1][0]:
                    found.append((n, False))
                    n = False
        except StopIteration:
            n = False
        found.append((e, n))
    for t, e in c:
        found.append((e, False))
    return found


684
3
задан 19 июля 2011 в 06:07 Источник Поделиться
Комментарии
2 ответа

def brace_check(string):

строка является именем модуль Python, было бы лучше, чтобы избежать этого

    # Imports
import re

импорт должен осуществляться на уровне модуля не внутри функции

    # Configuration
charset = dict(opening='{[(<',\
closing='}])>',\
string = ['"', "'"],\
single=['#', '//'],\
multi=[['/*', '*/'], '"""', ['<!--', '-->']])

Значения констант должны быть на уровне модуля не внутри функции

    found = []# found objects

нашли не до пути позже. Объявить его позже.

    notr = []# busy locations

Нотр и его комментарий не предлагаю все то же самое.

    temp = {}# temporary holding for opening braces
end = {}# temporary holding for closing braces

Все переменные являются временными. Не давать имена или комментарии, которые говорят мне такие очевидные вещи

    # Find all ocurrances and its position
newline = [m.start() for m in re.finditer('\n', string)] # every newline

for mn in charset['multi']:# find every multiline comment
if type(mn) == type(str()):# if there only is one element
op = [m.start() for m in re.finditer(re.escape(mn), string)]
cl = op[1::2]
op = op[0::2]
mn = (mn, mn)

else:
op = [m.start() for m in re.finditer(re.escape(mn[0]), string)]
cl = [m.start() for m in re.finditer(re.escape(mn[1]), string)]

Эти короткие загадочное название переменных просят путаницы.

        for i in xrange(len(op)):# find and close every comment
om = op[i]

Воспользуйтесь функцией перечислить. Это позволяет использовать цикл foreach и сделать индексы в то же время
попробуйте:
см = следующий(с V с V в п. Если V > ом) + лен(Миннесота[1])

добавить строку типа: start_comment, end_comment = МН, таким образом, вы можете избежать индексы код будет понятнее.

                if mn[0][0] in charset['opening'] and\
mn[1][-1] in charset['closing']:
for i in xrange(om + 1, cm - 1):
if i not in notr:
notr.append(i)

А постоянно проверять, является ли значение в Нотр, использовать набор. То последние три строчки можно просто быть дома.добавить( xrange(АМ + 1, см - 1) )

                else:
for i in xrange(om, cm):
if i not in notr:
notr.append(i)

Мы действительно нужно это особый случай?

            except:

Не перехватывать все исключения, вы будете скрывать ошибки таким образом. Вместо этого, поймать только определенный тип исключения, который вас интересует. Кроме того, вы хотите, как мало кода в блоке try, как это возможно, чтобы не простудиться других бродячих исключения

                for i in xrange(om, len(string)):
if i not in notr:
notr.append(i)

Вам как минимум нужен комментарий, объясняющий, почему это имеет смысл.

        del op, cl

Не переменные деле, его редко полезно.

    for sn in charset['single']:
rep = [m.start() for m in re.finditer(re.escape(sn), string)]
for s in rep:
try:
new = next(v for v in newline if v > s)
except:
new = len(string)
newline.append(len(string))

Почему бы не использовать строковые функции поиска, а затем построив новую строку списка? Также, если вам нужно обработать конца входной строки, положить, что в при создании списка не в обработчик исключений.

            if not s in notr:
for i in xrange(s, new):
if i not in notr:
notr.append(i)
newline.remove(new)
del rep

for sn in charset['string']:
rep = [m.start() for m in re.finditer(re.escape(sn), string)]
last = False
for i in xrange(len(rep)):
if not last:
s = rep[i]
if s not in notr:
try:
new = next(v for v in newline if v > s)
except:
new = len(string)
newline.append(len(string))

Если код повторяется, вам нужна функция.

                    try:
n = next(v for v in rep if v > s)
except:
n = new + 1
if n < new:
last = True
for i in xrange(s, n + 1):
if i not in notr:
notr.append(i)
else:
for i in xrange(s, new):
if i not in notr:
notr.append(i)
newline.remove(new)
else:
last = False
del rep

for cn in charset['closing']:
on = charset['opening'][charset['closing'].find(cn)]
end[on] = [m.start() for m in re.finditer(re.escape(cn), string)\
if m.start() not in notr]

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

    for on in charset['opening']:
op = [m.start() for m in re.finditer(re.escape(on), string)\
if m.start() not in notr]
for i in xrange(len(op)):
temp[op[i]] = on

for k in sorted(temp.keys(), reverse=True):
try:
c = next(v for v in end[temp[k]] if v > k and v not in notr)
end[temp[k]].remove(c)
for i in xrange(k, c + 1):
if i not in notr:
notr.append(i)
except:
c = False
found.append((k, c))

Мне кажется, что с помощью стека будет проще то, что вы делаете здесь.

    for v in end.values():
for c in v:
found.append((c, False))

Никакое объяснение не дано для того, что вы ставите внутри нашли. Я не знаю, что возвращаемое значение означает.
возвращение найден

Общие мысли:

Код усложняется, она действительно должна быть разделена на множество функций.

А потом все, что код соответствия различных типов комментариев и строк, имеют множество игнорировать регулярные выражения. Регулярное выражение должно соответствовать всему комментарий или строку, которая затем может быть удалена.

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

Мой переписанный код: (я не начать с вашего кода, но она должна поддерживать те же функции:)

from nose.tools import assert_equal
import re

class SimpleTokenizer(object):
"""
The constructor takes a dictionary of keys which should be regular
expression strings to arbitrary value. The tokenize method will produce
all the substrings in the text which match the regular expression.
It will return the value provided in the original dictionary
to identify which expression was matched
"""
def __init__(self, data):
# I need a consistent order from data, so I dump the dictionary
# into a list
data = list(data.items())
self.values = [value for key, value in data]
# this regular expression matches any key
self.expression = '|'.join('(%s)' % key for key, value in data)

def tokenize(self, text):
for match in re.finditer(self.expression, text):
# group 0 is the whole string, we subtract one
# to make up for that
yield match.start(), self.values[match.lastindex - 1]

CLOSER = 0
OPENER = 1
IGNORE = 2
class Language(object):
"""
Provides brace checking
"""
def __init__(self, opening, closing, ignore = ()):
"""
opening and closing should be sequences of the same size denoting
the start and end symbols that should matched. Ignore should be a
sequence of regular expression which should be ignored for the
purpose of matching such as comments, strings, etc.
"""

data = {}
for opener, closer in zip(opening, closing):
data[re.escape(opener)] = (OPENER, closer)
data[re.escape(closer)] = (CLOSER, closer)
for ignore in ignore:
data[ignore] = (IGNORE, None)
self._tokenizer = SimpleTokenizer(data)

def check(self, text):
"""
Given text produces the location of the various braces
returns a list of tuple, start, end where a pair of matches
braces exist. If either brace is missing it will be recorded
as None.
"""

braces = []

waiting = []
# waiting is a stack holding the braces which have been opened
# but not yet closed
for idx, (category, extra) in self._tokenizer.tokenize(text):
if category == OPENER:
waiting.append( (extra, len(braces)) )
# we start with None as the end of a brace, it'll be
# updated if we find it
braces.append( (idx, None) )
elif category == CLOSER:
# find the last entry that matches
index = None
for element, element_index in reversed(waiting):
if element == extra:
index = element_index
break

if index is None:
# no matches found
# in that case, record the start as None
braces.append( (None, idx) )
else:
# we found the match, replace the existing record
# with a new one
position, waste = braces[index]
braces[index] = (position, idx)
# elminate anything we had to ignore
del waiting[index:]

return braces

LANGUAGE_TESTS = [
("[()]", [(0, 3), (1, 2)]),
("[(a)]", [(0, 4), (1, 3)]),
("[(]", [(0, 2), (1, None)]),
("[()", [(0, None), (1, 2)]),
("[(])", [(0, 2), (1, None), (None,3)]),
("])", [(None, 0), (None, 1)]),
("(])", [(0, 2), (None, 1)]),
]

def test_basic_language():
language = Language(
opening = '[(',
closing = '])')
def inner(text, expected):
result = language.check(text)
assert_equal(list(result), expected)

for text, expected in LANGUAGE_TESTS:
yield inner, text, expected

STRING_LANGUAGE = [
('[(")]")]', [(0, 7), (1, 6)])
]
def test_string_language():
language = Language(
opening = '[(',
closing = '])',
ignore = [r'"[^"]*"']
)
def inner(text, expected):
result = language.check(text)
assert_equal(list(result), expected)

for text, expected in STRING_LANGUAGE:
yield inner, text, expected

6
ответ дан 20 июля 2011 в 11:07 Источник Поделиться

Вы можете оставить дель заявления. Они не сильно помогут.

Это гораздо проще разбить это на отдельные функции и просто позволить обычные правила пространства имен в Python обрабатывать удаление.

В случае, если тип(МН) == тип(ул()):# если есть только один элемент является излишне объем кода в один особый случай, который не совсем особенным.

Сделать '"""' совершенно отдельно от мульти и удалить ненужные , если заявление. Процесс его в отдельный проход без если заявление в петле.

Золотое правило: если отчетность не дорого. Найти способы удалить их.

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

Также. мульти, один и строки не правильные списки. Они незыблемы кортежей. Ликвидировать немного возможные накладные расходы, делая их правильного кортежей.

строки = [м.Start() для М в re.finditer('\п', строка)] # каждую строку может быть излишняя сложность. В одном случае символ новой строки является неявным "закрытия" как "единое" комментарии. Пожалуй, один должен быть ( ('#','\п'), ('//','\п) ) так что он может быть точно так же, как мульти.

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

В этом случае, однако, это хуже. Если если не последние в верхней части петли есть для перехода на следующий элемент в итераторе (xrange(лен(рэп)))

Есть две более эффективные способы, чтобы справиться с этим, как с явным итератор объектов.

Это минимально разрушительным

range_iter= iter( xrange( len( rep ) ) )
for i in range_iter:
s= rep[i]
... much logic ...
next( range_iter ) # Skip the next item. No last=True business.
... more logic ...

Это то, что вы имели в виду. Назначить С из респ напрямую.

rep_iter = iter( rep )
for s in rep_iter:
... much logic ...
next( rep_iter ) # Skip the next item. No last=True
... more logic ...

2
ответ дан 19 июля 2011 в 10:07 Источник Поделиться