pyparsing質問
-
19-09-2019 - |
質問
このコードは動作します:
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」「郵便番号」に解析しますが、どのように私は、この使用してpyparsingを決定するのですか?私は、その内容の文字列を解析していないよしかし、単にそれがクエリの種類を決定します。
解決
あなたの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と郵便番号式に解析アクションを取り付けることにより、解析時にこれを行うことができます:
# 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は、(ワード、キーワード、リテラル、CaselessLiteralとして)だけで正規表現よりも多くの解析クラスを提供し、あなたは「+」、それらを組み合わせることで、あなたのパーサを構成する「|」、「^」、「〜」「@」と'*' 演算子。たとえば、あなたが米国の社会保障番号を解析したかったが、正規表現を使用しない場合は、使用することができます:
ssn = Combine(Word(nums,exact=3) + '-' +
Word(nums,exact=2) + '-' + Word(nums,exact=4))
Wordが単一のトークンにマッチしたトークンを連結組み合わせて、そのコンストラクタで指定した文字で構成された連続的な「言葉」のために一致します。
あなたが「/」sので区切られ、このような数字の潜在的なリストのために解析したい場合は、使用します:
delimitedList(ssn, '/')
または全くdelimtersと、1と3の間、そのような数字があった場合、使用
ssn * (1,3)
そして任意の式は、結果の名前を持っているか、それらに添付の行動を解析し、さらに解析中に解析された結果、または機能性を豊かにすることができます。あなたも、フォワードクラスを使用してなど、括弧のネストしたリスト、算術式、として再帰的なパーサを構築することができます。
私は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']
(の漏れに注意末尾単一 '?')
他のヒント
あなたは、別途郵便番号やFOOを使用することができます。
zipresults = zipcode.parseString( t )
fooresults = foo.parseString( t )
私はpyparsing
モジュールを持っていないが、クラスではなく、機能Regex
にする必要があります。
あなたにできることはそれからサブクラスとオーバーライドメソッドです。