2017-07-09 1 views
2

文字列"Hello4.2this.is random 24 text42"が与えられた場合、すべての整数または浮動小数点数を返したい。[4.2, 24, 42]。その他の質問には24の戻り値があります。数字の横に数字以外の文字があっても、浮動小数点数を返したいと思います。私はPythonを初めて使っているので、正規表現やその他の複雑なインポートを避けようとしています。私はどのように始めるのか分かりません。助けてください。ここにいくつかの研究の試みがあります:Python: Extract numbers from a string、これは4.2と42を認識しないので動作しませんでした。悲しいことに4.242を認識するものはありません。指定された文字列のすべての浮動小数点数または整数を見つける

+4

あなたはこれをうまくやっていないでしょう。正規表現を使用する:このタスクのために存在します。 –

+0

@AlexanderHuszagh:*「あなたはこれをうまくやらなくてはいけません。」*まあ、それは挑戦のように聞こえる... –

+0

@WarrenWeckesser、彼らのキーワードは*よく*。それは間違いなく実行可能ですが、それは効率的ではなく、可読性がありません。 –

答えて

4

perldoc perlretutから正規表現:

import re 
re_float = re.compile("""(?x) 
^
     [+-]?\ *  # first, match an optional sign *and space* 
     (   # then match integers or f.p. mantissas: 
      \d+  # start out with a ... 
      (
       \.\d* # mantissa of the form a.b or a. 
     )?  # ? takes care of integers of the form a 
     |\.\d+  # mantissa of the form .b 
    ) 
     ([eE][+-]?\d+)? # finally, optionally match an exponent 
    $""") 
m = re_float.match("4.5") 
print m.group(0) 
# -> 4.5 

は、文字列からすべての番号を取得するには、次の正規表現を使用して

str = "4.5 foo 123 abc .123" 
print re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", str) 
# -> ['4.5', ' 123', ' .123'] 
+0

これは私のリーグより優れています。 +1 –

+0

+1正規表現はわかりませんが、なぜこれが理にかなっているのか直感的に理解できます。また、2番目のスニペットでトリプルストリングを使用した特定の理由はありますか? –

2

は、この問題のためにあなたの最も簡潔なコードを与える可能性があります。簡潔さに打ち勝つのは難しいです

re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", str) 

からpythadさんの答えです。

しかし、「正規表現を避けようとしています」と言っているので、ここでは正規表現を使用しない方法があります。明らかに、正規表現を使用するソリューション(おそらくはるかに遅い)よりも少し長くなりますが、それは複雑ではありません。

コードは入力文字を1文字ずつループします。 文字列から各文字を引き出すときに、(現在解析中の数字を保持する文字列)に追加します。を付加しても有効な数字が維持されます。 currentに追加できない文字に遭遇すると、current'''.''-'または'-.'のいずれかではなく、数字のリストに保存されます。これらは潜在的に数字を始める可能性のある文字列ですが、それ自体は有効な数字ではありません。

currentを保存すると、末尾に'e','e-'または'e+'が削除されます。それは'1.23eA'のような文字列で起こります。その文字列の解析中にcurrentは最終的に'1.23e'になりますが、'A'が発生します。つまり、文字列には有効な指数部が含まれていないため、'e'は破棄されます。

currentを保存した後、リセットされます。通常current''にリセットされますが、currentを保存する文字が'.'または'-'の場合、その文字は新しい番号の先頭になる可能性があるため、currentがその文字に設定されています。

ここには、機能extract_numbers(s)があります。 return numbersの前の行は、文字列のリストを整数と浮動小数点値のリストに変換します。文字列だけが必要な場合は、その行を削除します。

def extract_numbers(s): 
    """ 
    Extract numbers from a string. 

    Examples 
    -------- 
    >>> extract_numbers("Hello4.2this.is random 24 text42") 
    [4.2, 24, 42] 

    >>> extract_numbers("2.3+45-99") 
    [2.3, 45, -99] 

    >>> extract_numbers("Avogadro's number, 6.022e23, is greater than 1 million.") 
    [6.022e+23, 1] 
    """ 
    numbers = [] 
    current = '' 
    for c in s.lower() + '!': 
     if (c.isdigit() or 
      (c == 'e' and ('e' not in current) and (current not in ['', '.', '-', '-.'])) or 
      (c == '.' and ('e' not in current) and ('.' not in current)) or 
      (c == '+' and current.endswith('e')) or 
      (c == '-' and ((current == '') or current.endswith('e')))): 
      current += c 
     else: 
      if current not in ['', '.', '-', '-.']: 
       if current.endswith('e'): 
        current = current[:-1] 
       elif current.endswith('e-') or current.endswith('e+'): 
        current = current[:-2] 
       numbers.append(current) 
      if c == '.' or c == '-': 
       current = c 
      else: 
       current = '' 

    # Convert from strings to actual python numbers. 
    numbers = [float(t) if ('.' in t or 'e' in t) else int(t) for t in numbers] 

    return numbers 
+0

+1ありがとう!あなたのコードは素晴らしいです。私は主に正規表現のないソリューションを求めていたので、実際のコーディングの背後にあるロジックを理解することができました。そしてJSとCが正規表現を持っていないということを知る限りです。 –

関連する問題