1

このコードは機能します:

from pyparsing import *

zipRE = "\d{5}(?:[-\s]\d{4})?" 
fooRE = "^\!\s+.*"

zipcode = Regex( zipRE )
foo = Regex( fooRE )

query = ( zipcode | foo )



tests = [ "80517", "C6H5OH", "90001-3234", "! sfs" ]

for t in tests:
    try:
        results = query.parseString( t )
        print t,"->", results
    except ParseException, pe:
        print pe

私は2つの問題で立ち往生しています:

1 - カスタム関数を使用してトークンを解析する方法。たとえば、正規表現の代わりにカスタム ロジックを使用して、数値が郵便番号かどうかを判断したいとします。それ以外の:

zipcode = Regex( zipRE )

多分:

zipcode = MyFunc()

2 - 文字列が TO を解析するものをどのように判断しますか。「80001」は「zipcode」に解析されますが、pyparsing を使用してこれを判断するにはどうすればよいですか? 文字列の内容を解析するのではなく、単にそれがどのような種類のクエリであるかを判断するだけです。

4

3 に答える 3

3

zipcode と foo を別々に使用して、文字列がどちらに一致するかを知ることができます。

zipresults = zipcode.parseString( t )
fooresults = foo.parseString( t )
于 2010-02-06T11:20:05.887 に答える
2

2 番目の質問は簡単なので、最初にお答えします。クエリを変更して、結果の名前をさまざまな式に割り当てます。

query = ( zipcode("zip") | foo("foo") ) 

これで、返された結果に対して getName() を呼び出すことができます。

print t,"->", results, results.getName()

与える:

80517 -> ['80517'] zip
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1)
90001-3234 -> ['90001-3234'] zip
! sfs -> ['! sfs'] foo

結果の fooness または zipness を使用して別の関数を呼び出す場合は、解析アクションを foo および zipcode 式に添付することにより、解析時にこれを行うことができます。

# enclose zipcodes in '*'s, foos in '#'s
zipcode.setParseAction(lambda t: '*' + t[0] + '*')
foo.setParseAction(lambda t: '#' + t[0] + '#')

query = ( zipcode("zip") | foo("foo") ) 

今与えます:

80517 -> ['*80517*'] zip
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1)
90001-3234 -> ['*90001-3234*'] zip
! sfs -> ['#! sfs#'] foo

最初の質問については、どのような機能を意味するのか正確にはわかりません。Pyparsing は、正規表現 (Word、Keyword、Literal、CaselessLiteral など) よりも多くの解析クラスを提供し、それらを '+'、'|'、'^'、'~'、'@' および「*」演算子。たとえば、米国の社会保障番号を解析したいが、正規表現を使用したくない場合は、次を使用できます。

ssn = Combine(Word(nums,exact=3) + '-' + 
        Word(nums,exact=2) + '-' + Word(nums,exact=4))

コンストラクター内の指定された文字で構成される連続した「単語」の単語が一致し、Combine は一致したトークンを単一のトークンに連結します。

'/' で区切られたそのような番号の潜在的なリストを解析したい場合は、次を使用します。

delimitedList(ssn, '/')

または、そのような数字が 1 ~ 3 個あり、区切り文字がない場合は、次を使用します。

ssn * (1,3)

また、任意の式に結果名または解析アクションを関連付けて、解析結果または解析中の機能をさらに充実させることができます。Forward クラスを使用して、ネストされた括弧のリスト、算術式などの再帰パーサーを構築することもできます。

私が pyparsing を書いたときの私の意図は、基本的なビルディング ブロックからのパーサーのこの構成が、パーサーを作成するための主要な形式になるということでした。正規表現を究極の逃避弁として追加したのは、後のリリースになってからです (私がそうだったと思っていたもの)。人々がパーサーを構築できなかった場合、正規表現の形式に頼ることができました。

または、別のポスターが示唆しているように、pyparsing ソースを開き、既存のクラスの 1 つをサブクラス化するか、構造に従って独自のクラスを作成することができます。ペア文字に一致するクラスは次のとおりです。

class PairOf(Token):
    """Token for matching words composed of a pair
       of characters in a given set.
    """
    def __init__( self, chars ):
        super(PairOf,self).__init__()
        self.pair_chars = set(chars)

    def parseImpl( self, instring, loc, doActions=True ):
        if (loc < len(instring)-1 and 
           instring[loc] in self.pair_chars and
           instring[loc+1] == instring[loc]):
            return loc+2, instring[loc:loc+2]
        else:
            raise ParseException(instring, loc, "Not at a pair of characters")

となることによって:

punc = r"~!@#$%^&*_-+=|\?/"
parser = OneOrMore(Word(alphas) | PairOf(punc))
print parser.parseString("Does ** this match @@@@ %% the parser?")

与えます:

['Does', '**', 'this', 'match', '@@', '@@', '%%', 'the', 'parser']

(末尾のシングル '?' の省略に注意してください)

于 2010-02-06T16:41:10.517 に答える
2

私はpyparsingモジュールを持っていませんがRegex、関数ではなくクラスでなければなりません。

できることは、それをサブクラス化し、必要に応じてメソッドをオーバーライドして動作をカスタマイズし、代わりにサブクラスを使用することです。

于 2010-02-06T11:51:31.063 に答える