6

文字列の値の型を決定する関数を Python で作成しようとしています。例えば

文字列が 1 または 0 または True または False の場合、値は BIT です

文字列が 0-9* の場合、値は INT です

文字列が 0-9+.0-9+ の場合、値は float です

文字列が stg more (テキストなど) の場合、値はテキストです

これまでのところ、stgが好きです

def dataType(string):

 odp=''
 patternBIT=re.compile('[01]')
 patternINT=re.compile('[0-9]+')
 patternFLOAT=re.compile('[0-9]+\.[0-9]+')
 patternTEXT=re.compile('[a-zA-Z0-9]+')
 if patternTEXT.match(string):
     odp= "text"
 if patternFLOAT.match(string):
     odp= "FLOAT"
 if patternINT.match(string):
     odp= "INT"
 if patternBIT.match(string):
     odp= "BIT"

 return odp 

しかし、私はPythonで正規表現を使用することにあまり熟練していません..何が間違っているのか教えてください。たとえば、Text である必要がある 2010-00-10 では機能しませんが、INT または 20.90 であり、float である必要がありますが int です。

4

4 に答える 4

22

正規表現の道を行き過ぎる前に、 ast.literal_evalの使用を検討しましたか?

例:

In [35]: ast.literal_eval('1')
Out[35]: 1

In [36]: type(ast.literal_eval('1'))
Out[36]: int

In [38]: type(ast.literal_eval('1.0'))
Out[38]: float

In [40]: type(ast.literal_eval('[1,2,3]'))
Out[40]: list

Python を使用して解析することもできます。

OK、これはより大きな例です:

import ast, re
def dataType(str):
    str=str.strip()
    if len(str) == 0: return 'BLANK'
    try:
        t=ast.literal_eval(str)

    except ValueError:
        return 'TEXT'
    except SyntaxError:
        return 'TEXT'

    else:
        if type(t) in [int, long, float, bool]:
            if t in set((True,False)):
                return 'BIT'
            if type(t) is int or type(t) is long:
                return 'INT'
            if type(t) is float:
                return 'FLOAT'
        else:
            return 'TEXT' 



testSet=['   1  ', ' 0 ', 'True', 'False',   #should all be BIT
         '12', '34l', '-3','03',              #should all be INT
         '1.2', '-20.4', '1e66', '35.','-   .2','-.2e6',      #should all be FLOAT
         '10-1', 'def', '10,2', '[1,2]','35.9.6','35..','.']

for t in testSet:
    print "{:10}:{}".format(t,dataType(t))

出力:

   1      :BIT
 0        :BIT
True      :BIT
False     :BIT
12        :INT
34l       :INT
-3        :INT
03        :INT
1.2       :FLOAT
-20.4     :FLOAT
1e66      :FLOAT
35.       :FLOAT
-   .2    :FLOAT
-.2e6     :FLOAT
10-1      :TEXT
def       :TEXT
10,2      :TEXT
[1,2]     :TEXT
35.9.6    :TEXT
35..      :TEXT
.         :TEXT

そして、同じ結果を生成する正規表現ソリューションが確実に必要な場合は、次のとおりです。

def regDataType(str):
    str=str.strip()
    if len(str) == 0: return 'BLANK'

    if re.match(r'True$|^False$|^0$|^1$', str):
        return 'BIT'
    if re.match(r'([-+]\s*)?\d+[lL]?$', str): 
        return 'INT'
    if re.match(r'([-+]\s*)?[1-9][0-9]*\.?[0-9]*([Ee][+-]?[0-9]+)?$', str): 
        return 'FLOAT'
    if re.match(r'([-+]\s*)?[0-9]*\.?[0-9][0-9]*([Ee][+-]?[0-9]+)?$', str): 
        return 'FLOAT'

    return 'TEXT' 

ただし、ast バージョンよりも正規表現をお勧めすることはできません。正規表現で解釈するのではなく、これらのデータ型が何であるかをPythonに解釈させてください...

于 2012-04-21T17:15:12.610 に答える
5

json を使用することもできます。

import json
converted_val = json.loads('32.45')
type(converted_val)

出力

type <'float'>

編集

ただし、質問に答えるには:

re.match()文字列の先頭から部分一致を返します。すべてのパターン一致を評価し続けるため、「2010-00-10」のシーケンスは次のようになります。

if patternTEXT.match(str_obj): #don't use 'string' as a variable name.

一致するため、odp「テキスト」に設定されます

次に、スクリプトは次のことを行います。

if patternFLOAT.match(str_obj):

一致しません、odpまだ「テキスト」に等しい

if patternINT.match(str_obj):

部分一致odpは「INT」に設定されています

match は部分一致を返すため、複数のifステートメントが評価され、最後に評価されたステートメントによって、 に返される文字列が決まりますodp

次のいずれかを実行できます。

  1. 最後に一致するものが正しいものになるように、if ステートメントの順序を並べ替えます。

  2. 一致する最初のステートメントのみが評価されるように、ステートメントの残りの部分にifandを使用します。elifif

  3. 一致オブジェクトが文字列全体と一致していることを確認します。

    ...
    match = patternINT.match(str_obj)
    if match:
        if match.end() == match.endpos:
            #do stuff
    ...
    
于 2012-04-21T17:17:04.590 に答える
2

これらを入力に使用したと言いました:

  • 2010-00-10 (テキストではなく int でした)
  • 20.90 (浮動小数点ではなく整数)

元のコード:

def dataType(string):

 odp=''
 patternBIT=re.compile('[01]')
 patternINT=re.compile('[0-9]+')
 patternFLOAT=re.compile('[0-9]+\.[0-9]+')
 patternTEXT=re.compile('[a-zA-Z0-9]+')
 if patternTEXT.match(string):
     odp= "text"
 if patternFLOAT.match(string):
     odp= "FLOAT"
 if patternINT.match(string):
     odp= "INT"
 if patternBIT.match(string):
     odp= "BIT"

 return odp 

問題

あなたのifステートメントは順番に実行されます - つまり:

if patternTEXT.match(string):
    odp= "text"
if patternFLOAT.match(string):
    odp= "FLOAT"
if patternINT.match(string)
    odp= "INT"
if patternBIT.match(string):
    odp= "BIT"

"2010-00-10" はテキスト パターンと一致しますが、フロート パターンとの一致を試み ( がないため失敗します.)、次にパターンとの一致を試みます。intこれは が含まれているため機能します[0-9]+

以下を使用する必要があります。

if patternTEXT.match(string):
    odp = "text"
elif patternFLOAT.match(string):
    ...

あなたの状況では、おそらく、より具体的なものからより具体的でないものへと移行したいと思うでしょう。「テキスト」パターンは英数字入力にのみ一致し、特殊記号には一致しないため、正規表現も改善する必要があります。

私はASTソリューションの方が好きですが、私自身の提案をします:

def get_type(string):

    if len(string) == 1 and string in ['0', '1']:
        return "BIT"

    # int has to come before float, because integers can be
    # floats.
    try:
        long(string)
        return "INT"
    except ValueError, ve:
        pass

    try:
        float(string)
        return "FLOAT"
    except ValueError, ve:
        pass

    return "TEXT"

実行例:

In [27]: get_type("034")
Out[27]: 'INT'

In [28]: get_type("3-4")
Out[28]: 'TEXT'


In [29]: get_type("20.90")
Out[29]: 'FLOAT'

In [30]: get_type("u09pweur909ru20")
Out[30]: 'TEXT'
于 2012-04-21T17:48:03.887 に答える
1

に返信して

たとえば、2010-00-10では機能しません。これはTextである必要がありますが、INTまたは20.90であり、floatである必要がありますがintです。

>>> import re
>>> patternINT=re.compile('[0-9]+')
>>> print patternINT.match('2010-00-10')
<_sre.SRE_Match object at 0x7fa17bc69850>
>>> patternINT=re.compile('[0-9]+$')
>>> print patternINT.match('2010-00-10')
None
>>> print patternINT.match('2010')
<_sre.SRE_Match object at 0x7fa17bc69850>

$文字列の終わりを制限することを忘れないでください。

于 2012-04-21T18:13:04.813 に答える