74111


Pythonでテキストファイルの読み込みを行いたいです。

[code]

    Value : ********  -12.345   *****
    
[/code]

という内容のファイルから、`-12.345` の部分だけを抜き出すにはどうすればよいでしょうか。  
ファイルによって -（マイナス）がついていたりついていなかったりするのですが、ここを一般化した書き方がわかりません。  
よい書き方があれば、ご教示いただけますでしょうか。


CC BY-SA 4.0
2021-02-18T07:35:44.613
74100
2021-03-08T17:12:16.800
2021-02-18T12:01:21.550
7290
41680
question
python 正規表現
Pythonでテキストファイルから負値を含む数字の抽出をしたい

[code]

    #!/usr/bin/env python3
    #-*- coding: utf-8 -*-↲
    
    import re
    # *** number *** 
    # ** で囲われた数字が１つあるという前提
    # 全角数字は含めない場合
    
    d = """
    Value : *** ー１０ ***
    Value : ** -100 -200 -201.1 ***
    Value : ***** -１０００ ***
    Value : ******** -12.345 *****
    Value : ******** 12.345 *****
    Value : ******** -112.345 *****
    Value : ******** -12.345 *****
    """
    
    pattern = r'\*+ ((-[0-9]+\.[0-9]+)|(-[0-9]+\.)|(-[0-9]+)) \*+'
    
    matchs = re.finditer(pattern, d)
    for match in matchs:
        print(match.groups()[0])
    
[/code]


CC BY-SA 4.0
2021-02-18T11:18:50.447
74104
2021-02-18T11:18:50.447
43957
74100
answer


文字列の途中にほかに数字が入っていないと仮定するなら, こんな風にできます

[code]

    import re
    
    s = 'Value : ******** -12.345 *****'
    m = re.search(r'-?[\d\.]+', s)
    if m:
        print(f'数値は {m[0]}')
    
[/code]

もし何度も使うようなら高速化のためにこんな風に

[code]

    import re
    
    num = re.compile(r'-?[\d\.]+')
    
    # 何度も処理を行う部分
    m = num.search(s)
    if m:
        print(f'数値は {m[0]}')
    
[/code]

(注意)  
[re --- 正規表現操作](https://docs.python.org/ja/3/library/re.html) の「任意の Unicode 10
進数字」と小数点, の連続にマッチさせていますが, 文字列の中に全角の数字とか入ってるとヒットするはずなので, 文字列データによってはこれではマズイかも

* * *

(注意点についての補足 追記)  
なので状況に応じて `re.ASCII`指定する必要があるかもしれません

[code]

    import re
    
    num = re.compile(r'-?[\d\.]+', re.ASCII)
    s = 'Value : ******** -1１2.345 *****'
    
    m = num.search(s)
    if m:
        v = float(m[0])
        print(f'数値は {m[0]} ({v})') # 数値は -1 (-1.0)
    
[/code]

* * *

(更に追記)  
隠し文字ではなく本当に `'*'` が入っているだけならこんな方法も

[code]

    s = 'Value : ******** -1１2.345 *****'
    
    prefix = 'Value : '
    
    if s.startswith(prefix):
        s = s[len(prefix):]
    v = s.strip('*')
    print(float(v))
    
[/code]

Python3.9以降なら `removeprefix()`が利用できるのでもっと短く書くことも可能

[code]

    v = s.removeprefix(prefix).strip('* ')
    print(float(v))
    
[/code]


CC BY-SA 4.0
2021-02-18T11:46:51.973
74106
2021-03-08T17:12:16.800
2021-03-08T17:12:16.800
43025
43025
74100
answer


> そこから、アスタリスクに囲まれた数字をとってくるにはどうしたらいいのか

`float` に cast する方法があります。

[code]

    def isFloat(s):
      try:
        float(s)
        return True
      except ValueError:
        return False
    
    lines = [
      'Value : ********  -12.345   *****',
      'Value : ********-12.345*****',
      'Value : ********  -1.2345e-1*****',
      'Value : ********   12.345   *****',
      'Value : ********  +12.345   *****',
      'Value : ********1.*****',
      'Value : ********.5*****',
    ]
    
    for l in lines:
      print([num.strip() for num in filter(None, l.split('*')) if isFloat(num)])
    =>
    ['-12.345']
    ['-12.345']
    ['-1.2345e-1']
    ['12.345']
    ['+12.345']
    ['1.']
    ['.5']
    
[/code]


CC BY-SA 4.0
2021-02-18T13:07:20.853
74111
2021-02-18T13:07:20.853
74100
answer