5

タイヤを解析し始めたばかりで、これまでのところ気に入っていますが、小数の文字列を解析して数値データ型に変換するのに役立てることができませんでした。

たとえば、データベーステーブルの列の値に文字列が含まれている場合:

1 1/2

それをPythonに相当する数値に変換する方法が必要です。

1.5

分数の数値が整数であるか実数であるかを気にしないパーサーを作成したいと思います。たとえば、次のようにします。

1.0 1.0 / 2.0

...まだ翻訳する:

1.5

基本的に、パーサーは概念的に次のことを実行する必要があります。

「11/2」=1+ 0.5 = 1.5

次のサンプルコードは私たちを近づけるようです...

http://pyparsing.wikispaces.com/file/view/parsePythonValue.py

...しかし、前進するのに十分な距離ではありません。小数ハンドラーを作成するためのすべてのテストは、式(1)の最初の部分のみを返します。チップ?ヒント?タイムリーな知恵?:)

4

4 に答える 4

8

あなたはいくつかのテストを引用しているので、少なくとも問題を突き刺したように思えます。整数または実数の単一の数値をすでに定義していると仮定します-関係ありません、とにかくすべてを浮動小数点に変換しています-そして2つの数値の一部、おそらく次のようなものです:

from pyparsing import Regex, Optional

number = Regex(r"\d+(\.\d*)?").setParseAction(lambda t: float(t[0]))

fraction = number("numerator") + "/" + number("denominator")
fraction.setParseAction(lambda t: t.numerator / t.denominator)

(解析時に浮動小数点変換と分数除算を実行する解析アクションの使用に注意してください。後で戻ってふるいにかけるのではなく、何かが数値や分数などであることがわかっている場合は、解析中にこれを行うことを好みます。断片化された文字列の束を介して、パーサーがすでに実行した認識ロジックを再作成しようとします。)

これが私があなたの問題のために作成したテストケースで、整数と分数、そして整数と実数の両方を使用した整数と分数で構成されています。

tests = """\
1
1.0
1/2
1.0/2.0
1 1/2
1.0 1/2
1.0 1.0/2.0""".splitlines()

for t in tests:
    print t, fractExpr.parseString(t)

最後のステップは、単一の数値、分数、または単一の数値と分数である可能性のある分数式を定義する方法です。

pyparsingは左から右であるため、regexenと同じ種類のバックトラックは実行されません。したがって、この式はあまりうまく機能しません。

fractExpr = Optional(number) + Optional(fraction)

数値と小数部から得られる可能性のある数値を合計するには、次の解析アクションを追加します。

fractExpr.setParseAction(lambda t: sum(t))

私たちのテストは次のように印刷されます。

1 [1.0]
1.0 [1.0]
1/2 [1.0]
1.0/2.0 [1.0]
1 1/2 [1.5]
1.0 1/2 [1.5]
1.0 1.0/2.0 [1.5]

1/2分数だけを含むテストケースの場合、先頭の分子はOptional(number)用語に一致しますが、「/ 2」だけが残ります。これは一致しませんOptional(fraction)。幸い、2番目の用語はオプションであるため、これは「合格」です。 、しかしそれは本当に私たちが望むことをしていません。

孤独な数と分数の主要な分子の間にこの潜在的な混乱があるため、fractExprを少し賢くし、最初に孤独な分数を探す必要があります。これを行う最も簡単な方法は、fractExprに次のように読み取ることです。

fractExpr = fraction | number + Optional(fraction)

この変更により、テストの結果が改善されました。

1 [1.0]
1.0 [1.0]
1/2 [0.5]
1.0/2.0 [0.5]
1 1/2 [1.5]
1.0 1/2 [1.5]
1.0 1.0/2.0 [1.5]

pyparsingにはいくつかの古典的な落とし穴があり、これはそのうちの1つです。pyparsingは、指示した先読みのみを実行することを覚えておいてください。それ以外の場合は、左から右へのまっすぐな解析です。

于 2010-10-12T12:35:59.450 に答える
3

正確にはあなたが探しているものではありませんが...

>>> import fractions
>>> txt= "1 1/2"
>>> sum( map( fractions.Fraction, txt.split() ) )
Fraction(3, 2)
>>> float(_)
1.5
于 2010-10-12T10:25:31.183 に答える
2

このレシピは役立つかもしれません:

39行目を見てください。

mixed = Combine(numeral + fraction, adjacent=False, joinString=' ')
于 2010-10-12T05:32:22.477 に答える
1

これはS.Lottとは少し二重ですが、とにかくここにあります。

from fractions import Fraction
print sum(Fraction(part) for part in '1 1/2'.split())

ただし、floatの「整数」の処理は非常に複雑になります。

from fractions import Fraction
clean = '1.0 1.0/2.0'.replace('.0 ',' ').replace('.0/', '/').rstrip('0.').split()
print(clean)
print(sum(Fraction(part) for part in clean))

および他のポスターの例に加えて、空白を含む/を含むもの:

from fractions import Fraction

tests = """\
1
1.0
1/2
1.0/2.0
1 1/2
1.0 1/2
1.0 1.0/2.0
1.0 1.0 / 2.0
""".splitlines()

for t in tests:
    clean = t.replace('.0 ',' ').replace('.0/', '/').rstrip('0.').split()
    value = sum(Fraction(part) for part in clean)
    print('%s -> %s, %s = %f' % (t, clean, value, float(value)))
于 2010-10-12T10:46:04.377 に答える