跟踪序列中的开/关状态

时间:2014-10-04 11:12:27

标签: python generator

我有一个生成器功能,可以跟踪我是否在某对事件之间 - a" start"事件和"结束"事件。例如,它可以检查令牌并报告我是否在评论分隔符"/*""*/"之间(非嵌套)。以下代码有效,但有一个很好的itertools组合或逻辑重组可以简化它(和/或使它更多" pythonic")?

def tokspan(starttok, endtok, stream):
    inside = False
    for tok in stream:
        if (not inside) and tok == starttok:
            inside = True
        yield (inside, tok)
        if inside and tok == endtok:
            inside = False          

tstream = "int x; /* a non-nesting comment /* etc. */ x=1; main();".split()          
for status, tok in tokspan("/*", "*/", tstream):
    print(status, tok)

以上(有意)返回True作为边界令牌(/**/),但这并不是特别重要。如果你的方法恰好排除了一个或两个边界(比如python范围),我仍然想知道它。

2 个答案:

答案 0 :(得分:1)

我能想到的唯一简化就是围绕设置/重置inside重写逻辑:

def tokspan(starttok, endtok, stream):
    inside = False
    for tok in stream:
        inside |= (tok == starttok)
        yield (inside, tok)
        inside &= (tok != endtok)

这是否使得代码的可读性或多或少都在旁观者眼中。

答案 1 :(得分:0)

可能在这里使用装饰器。我不确定这对你是否有用,但这可能只是给你一些想法。

创建一个装饰器,用于存储您要过滤掉的项目:

import itertools as it

class insideDec(object):

    def __init__(self, start, stop):

        self.start = start
        self.stop  = stop

    def __call__(self, f):

        def wrapper(x):
            x1 = it.dropwhile(lambda m: not m.startswith(self.start), x  )
            x1.next()
            x2 = it.takewhile(lambda m: not m.startswith(self.stop),  x1 )
            return f(x2)

        return wrapper 

@insideDec('{', '}')
def f(val):
    return val

if __name__ == '__main__':
    print ''.join(f('This is some {string that needs to} be printed'))

现在您将装饰器应用于接受字符串的函数。这会将函数转换为输入为迭代器的函数。然后像处理任何其他迭代器一样处理迭代器。

当然,你总是可以在任何时候将迭代器转换为字符串(比如在这里):

        # rest of the code ...
        x2 = it.takewhile(lambda m: not m.startswith(self.stop),  x1 )
        return f(''.join(x2))
        # rest of the code ...

这真的取决于你......

编辑:

很抱歉。我误解了你的问题。对于标记化,可能以下内容可能会有所帮助吗?

class tokenize():

    def __init__(self, strVal, start, stop):
        self.start   = start
        self.stop    = stop
        self.strTees = it.tee(strVal, len(start))
        self.inside  = False
        for i, strTee in enumerate(self.strTees):
            for j in range(i):
                next(strTee, '')
        self.strVals = it.izip( *self.strTees )

    def __iter__(self):
        return self

    def next(self):

        v = ''.join(self.strVals.next())
        if v == '': raise StopIteration
        if v == self.start: self.inside = True
        if v == self.stop:  self.inside = False

        # print '[',v, ']'

        return (v[0], self.inside)


if __name__ == '__main__':

    strVal = 'int x; /* a non-nesting comment etc. */ x=1; main();'
    for x, y in tokenize( strVal, '/*', '*/' ):
        print x, y

同样,这并不完美,可能会达到你的目的......

这是输出:     我错了     n错     t错       假     x错     ;假       假     /真的     *是的       真正     一个真的       真正     是的     真的     是的      - 是的     是的     真的     真的     真的     我是真的     是的     克。真的       真正     是的     真的     是的     是的     真的     是的     真的       真正     真的     真的     是的     。真正       真正     *错     /错       假     x错     =假     1错     ;假       假     我错了     一个错误     我错了     n错     (错     )错误