3

RCS ファイル形式のパーサーを作成しようとしていますが、RCSadmin のコンテキストで RCSid を解析しようとすると、無限ループが発生します。問題のある行を削除する

        Group(ZeroOrMore(RCSid)).setResultsName('access') + \

ハングが発生しないようにします。RCSid は文字列の解析に成功しました。助言がありますか?

ここに私が持っているものがあります:

from   pyparsing import *
import string

# Special characters in the RCS file format
special = '$,.:;@'

RCSdigit = Word(nums, min=1, max=1).setName('RCSdigit')
RCSnum = Word(nums + '.').setName('RCSnum')
RCSidchar = CharsNotIn(special + string.whitespace).setName('RCSidchar')
RCSid = Combine(Optional(RCSnum) + ZeroOrMore(RCSidchar +
        ZeroOrMore(RCSidchar | RCSnum))).setName('RCSid')
RCSadmin = \
    Keyword('head').suppress() + \
        Optional(RCSnum).setResultsName('head') + \
        Suppress(';') + \
    Optional(Keyword('branch').suppress() +
        Optional(RCSnum).setResultsName('branch') +
        Suppress(';')
    ) + \
    Keyword('access').suppress() + \
        Group(ZeroOrMore(RCSid)).setResultsName('access') + \
        Suppress(';')

ids = ['.111abc111', '1111abc111', '1.11', '1', '1abc', 'abc',
        'abc1', 'abc1.11', 'abc.1111', '']
for i in ids:
    try:
        print i, RCSid.parseString(i)
    except ParseException, pe:
        print pe.markInputline()
for i in ids:
    line = 'head 3; branch 1; access ' + i + ';'
    try:
        print line, RCSadmin.parseString(line)
    except ParseException, pe:
        print pe.markInputline()

出力付き (^C at hang):

.111abc111 ['.111abc111']
1111abc111 ['1111abc111']
1.11 ['1.11']
1 ['1']
1abc ['1abc']
abc ['abc']
abc1 ['abc1']
abc1.11 ['abc1.11']
abc.1111 ['abc.1111']
 ['']
^Chead 3; branch 1; access .111abc111;
Traceback (most recent call last):
  File "sample.py", line 35, in <module>
    print line, RCSadmin.parseString(line)
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 1070, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 945, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 2352, in parseImpl
    loc, exprtokens = e._parse( instring, loc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 945, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 2604, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 945, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 2724, in parseImpl
    loc, tmptokens = self.expr._parse( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 945, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 2604, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 945, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 2336, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/lib/pymodules/python2.6/pyparsing.py", line 943, in _parseNoCache
    if self.mayIndexError or loc >= len(instring):
KeyboardInterrupt
4

1 に答える 1

1

空の文字列は本当に有効な RCSid ですか? ないと思います。admin ステートメントの access 句で RCSid を省略できる場合がありますが、すでに ZeroOrMore で処理しています。指定されたとおりにプリミティブを定義し、上位レベルの構成で Optional、ZeroOrMore などを考慮に入れます。

RCSid を次のように変更します。

RCSid = Combine(RCSnum + ZeroOrMore(RCSidchar + ZeroOrMore(RCSidchar | RCSnum))
                |
                OneOrMore(RCSidchar + ZeroOrMore(RCSidchar | RCSnum))).setName('RCSid')

すべてのテスト ケース (「」の一致を除く) に引き続き一致する結果が得られ、完全な RCSAdmin 文字列が適切に解析されます。

編集 これが私の完全なパーサーで、pyparsing 1.5.6で動作します:

# Special characters in the RCS file format
special = '$,.:;@'

RCSdigit = Word(nums, min=1, max=1).setName('RCSdigit')
RCSnum = Word(nums + '.').setName('RCSnum')
RCSidchar = CharsNotIn(special + string.whitespace).setName('RCSidchar')
#~ RCSid = Combine(Optional(RCSnum) + ZeroOrMore(RCSidchar +
        #~ ZeroOrMore(RCSidchar | RCSnum))).setName('RCSid')
RCSid = Combine(RCSnum + ZeroOrMore(RCSidchar + ZeroOrMore(RCSidchar | RCSnum))
                |
                OneOrMore(RCSidchar + ZeroOrMore(RCSidchar | RCSnum))).setName('RCSid')
RCSadmin = \
    Keyword('head').suppress() + \
        Optional(RCSnum).setResultsName('head') + \
        Suppress(';') + \
    Optional(Keyword('branch').suppress() +
        Optional(RCSnum).setResultsName('branch') + 
        Suppress(';')
    ) + \
    Keyword('access').suppress() + \
        Group(ZeroOrMore(RCSid)).setResultsName('access') + \
        Suppress(';') 
于 2011-08-29T16:46:19.600 に答える