投稿されたコードにはいくつかの小さなタイプミスがありました ( firstame="bob"
data vs. firstname="bob"
、lastname
vs. last
)。結果を印刷すると、次のようになります。
['firstname', 'bob', 'lastname', 'stewart', 'dob', '2010-0206',
'hobbies', 'reading, singing', 'drawing', 'is_minor', 'True']
最初に、list_of_names
(以前の SO の質問 pyparsing string of quoted namesから) 可能な値の型として定義したように、ブール値を定義して True/False 値を解析することをお勧めします。oneOf
文字列「True」と「False」から実際の Python ブール値に変換する解析アクションを追加しましょう。
boolean_value = oneOf("True False").setParseAction(lambda t: t[0]=='True')
これはremoveQuotes
、quotedString での使用に似ています。
これで、解析結果は次のようになります。
['firstname', 'bob', 'lastname', 'stewart', 'dob', '2010-0206',
'hobbies', 'reading, singing', 'drawing', 'is_minor', True]
True は文字列ではなく、Python の値であることに注意してくださいTrue
(値を引用符で囲む必要はありません)。
質問の最初の部分である、これを dict にする方法について説明します。Pyparsing を使用すると、文法のさまざまな部分の結果名を定義できるため、データが解析された後、それらの値に名前でアクセスできます。これを行うための構文は、メソッドを呼び出すことでしたsetResultsName
:
my_data = person_start + first.setResultsName("firstname") +
last.setResultsName("lastname") + ...
これはやや面倒で、すべての「.setResultsName」メソッド呼び出しで式が読みにくいことがわかりました。しばらく前に、この構文を受け入れるように API を変更しました。
my_data = person_start + first("firstname") + last("lastname") + ...
ただしfirst
、last
、 などとして定義したものには、値だけでなく、ラベルも含まれます。
文法を単純化する 1 つの方法は、独自の小さなヘルパー メソッドを作成することnamed_parameter
です。
def named_parameter(label, paramtype):
expr = Literal(label) + Suppress('=') + paramtype(label)
return expr
は、リテラル文字列と値の結果名のlabel
両方を指定するために使用されることに注意してください。これで、文法を次のように定義できます。
first = named_parameter("firstname", quotedString)
last = named_parameter("lastname", quotedString)
dob = named_parameter("dob", quotedString)
hobbies = named_parameter("hobbies", Suppress("[") + list_of_names + Suppress("]"))
is_minor = named_parameter("is_minor", boolean_value)
名前が付けられた値を使用して、解析された結果に Python dict としてアクセスできます。
print result["firstname"]
print result["hobbies"]
プリント:
bob
['reading, singing', 'drawing']
または、必要に応じて、オブジェクト属性表記を使用することもできます。
print result.firstname
print result.hobbies
質問の 2 番目の部分に答えるために、パラメーターが順不同である可能性がある場合の処理方法を尋ねました。これを行う最も簡単な方法は、delimitedList
再度使用することです。
parameter = first | last | dob | hobbies | is_minor
my_data = person_start + delimitedList(parameter) + person_end
これは厳密なパーサーではありません。すべてのパラメーターを持たないパラメーター リスト、または重複するパラメーターを含むリストを受け入れます。ただし、既存の有効なコードについては、パラメーターを含むリストを任意の順序で解析します。
最終的なパーサーは次のとおりです。
quotedString.setParseAction(removeQuotes)
list_of_names = delimitedList(quotedString)
boolean_value = oneOf("True False").setParseAction(lambda t: t[0]=='True')
def named_parameter(label, paramtype):
expr = Literal(label) + Suppress('=') + paramtype(label)
return expr
person_start = Literal("person(").suppress()
first = named_parameter("firstname", quotedString)
last = named_parameter("lastname", quotedString)
dob = named_parameter("dob", quotedString)
hobbies = named_parameter("hobbies", Suppress("[") + list_of_names + Suppress("]"))
is_minor = named_parameter("is_minor", boolean_value)
person_end = Suppress(")")
comma = Literal(",").suppress()
parameter = first | last | dob | hobbies | is_minor
my_data = person_start + delimitedList(parameter) + person_end