92845


**実行環境**

Windows 10  
Python 3.X

### やりたいこと

次の文字列を正規表現の `re.findall`
を使用して数値とmsとMBの二つの単位までを取得してリスト化したいと考えております。数値までを取得することはできたのですが、単位を取得することができませんでした。

文字列を次のリストのようにするために、頭文字と末尾を同時に取得したいのですが、うまくやり方が  
分かりません。初歩的な質問かもしれませんが教えていただけると幸いです。

#### 取得前の文字列

[code]

    'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    
[/code]

#### 取得したリスト

[code]

    ['123.45 ms', '123 ms', '123 MB', '123 MB', '1234.56 ms']
    
[/code]

### 試したこと

正規表現について知らべ、まず、数値までを取得することができました。

[code]

    string = 'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    stringlist = re.findall(r'\d+\.\d+|\d+', string)
    
[/code]

次に、末尾の指定する際に$を使用することは分かっていますので、次のようにコーディングしましたがリストとして何も取得できませんでした。

[code]

    string = 'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    stringlist = re.findall(r'\d+\.\d+ms$|\d+ms$', string)
    
[/code]


CC BY-SA 4.0
2022-12-17T14:36:14.007
92843
2022-12-23T07:34:30.397
2022-12-17T16:34:11.447
3060
47546
question
python 正規表現
Python で正規表現を使用し、頭文字と末尾を指定して文字列を取得したい

[code]

    import re
    
    string = 'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    stringlist = re.findall(r'(\d+(?:\.\d+)? .+?)(?=\t|$)', string)
    print(stringlist)
    
    # ['123.45 ms', '123 ms', '123 MB', '123 MB', '1234.56 ms']
    
[/code]

**re.split() を使う場合**

[code]

    stringlist = re.split(r': |\t', string)[1::2]
    print(stringlist)
    
    # ['123.45 ms', '123 ms', '123 MB', '123 MB', '1234.56 ms']
    
[/code]


CC BY-SA 4.0
2022-12-17T15:05:23.320
92845
2022-12-17T19:27:41.097
2022-12-17T19:27:41.097
47127
47127
92843
answer


別に何でもいいのですが、Matchオブジェクトを使う例もあった方がいいと思い回答してみました。( **やりたいことに反してfindallは使ってません**
)

# 仮定した仕様

  * 符号なし
  * 0省略なし
  * 科学技術表記なし
  * 単位との間にスペースが1つ固定
  * 単位はms/MBのみ
  * 単位の後に続く文字は見ない
  * 単位なしもありとする

## コード

[code]

    import re
    string = 'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    stringlist = [m[0] for m in re.finditer('(\d+(?:\.\d*)?)(?: (ms|MB))?',string)]
    print(stringlist)
    
    # ['123.45 ms', '123 ms', '123 MB', '123 MB', '1234.56 ms']
    
[/code]

## コンセプト

  * (Matchオブジェクトにすることで)数字と単位が個別に取得可能


CC BY-SA 4.0
2022-12-17T16:01:57.867
92847
2022-12-17T16:15:29.090
2022-12-17T16:15:29.090
54957
54957
92843
answer


> 次に、末尾の指定する際に$を使用すること

順に追っていくと  
まず数字と `'ms'`の間に空白があるので, それを考慮しないとヒットしません  
以下は `\s` 指定してるけど, `\s` は SPC以外にタブや改行文字などにもヒットするので, スペースのみなら
`\s`をスペースへ置き換えるとよいでしょう

[code]

    import re
    string = 'Duration: 123.45 ms\tBilled Duration: 123 ms\tMemory Size: 123 MB\tMax Memory Used: 123 MB\tInit Duration: 1234.56 ms'
    re.findall(r'\d+\.\d+\s*ms$|\d+\s*ms$', string)
    # ['1234.56 ms']
    
[/code]

`$`の「末尾」の意味は, (もう少し正確には) **行の末尾** です  
単語の末尾ならば `\b` が利用可能  
たとえば `re.findall(r'\b単語\b', '単語、英単語')` なら前者のみヒットし `'英単語'`にはヒットしない

[code]

    re.findall(r'\d+\.\d+\s*ms\b|\d+\s*ms\b', string)
    # ['123.45 ms', '123 ms', '1234.56 ms']
    
[/code]

もしくは `'\t'`を改行に置き換え, `re.MULTILINE` を指定すると複数行に対応

[code]

    re.findall(r'\d+\.\d+\s*ms$|\d+\s*ms$', string.replace('\t', '\n'),
                  flags=re.MULTILINE)
    # ['123.45 ms', '123 ms', '1234.56 ms']
    
[/code]

`'ms'`, `'MB'` に対応するには

[code]

    re.findall(r'\d+\.\d+\s*(?:ms|MB)\b|\d+\s*(?:ms|MB)\b', string)
    # ['123.45 ms', '123 ms', '123 MB', '123 MB', '1234.56 ms']
    
[/code]

しかし長くなるので, 数字部分は纏めて `\d+(?:\.\d+)?` のようにするとよいでしょう

[code]

    re.findall(r'\d+(?:\.\d+)?\s*(?:ms|MB)\b', string)
    
[/code]

参考: (docs.python.org) [re ---
正規表現操作](https://docs.python.org/ja/3/library/re.html)


CC BY-SA 4.0
2022-12-23T07:34:30.397
92977
2022-12-23T07:34:30.397
43025
92843
answer