2016-07-16 8 views
2

基本的な質問:グループおよびネストされた正規表現(テキストファイルからの単位変換)と命名グループ

はどのようにして、より大きな正規表現グループ内の別のグループの値と巣これでPythonの正規表現のグループに名前を付けることができますか?質問の

原産地:'Your favorite song is 1 hour 23 seconds long. My phone only records for 1 h 30 mins and 10 secs.'

何回を抽出するためのエレガントなソリューションであり、与えられた単位に変換などの文字列が与えられ

?ソリューションで

私の最高の推測では、辞書を作成し、目的の単位に変換した辞書で操作を実行するために、次のようになりますソリューションをしようとしました

string[0]: {'time1': {'day':0, 'hour':1, 'minutes':0, 'seconds':23, 'milliseconds':0}, 'time2': {'day':0, 'hour':1, 'minutes':30, 'seconds':10, 'milliseconds':0}} string[1]: {'time1': {'day':4, 'hour':2, 'minutes':3, 'seconds':6, 'milliseconds':30}} 

私は正規表現のソリューションを持っているが、私が望む何をしていません:

つまりはこれに与えられた文字列を変換

import re 

test_string = ['Your favorite song is 1 hour 23 seconds long. My phone only records for 1h 30 mins and 10 secs.', 
       'This video is 4 days 2h 3min 6sec 30ms'] 

year_units = ['year', 'years', 'y'] 
day_units = ['day', 'days', 'd'] 
hour_units = ['hour', 'hours', 'h'] 
min_units = ['minute', 'minutes', 'min', 'mins', 'm'] 
sec_units = ['second', 'seconds', 'sec', 'secs', 's'] 
millisec_units = ['millisecond', 'milliseconds', 'millisec', 'millisecs', 'ms'] 
all_units = '|'.join(year_units + day_units + hour_units + min_units + sec_units + millisec_units) 
print((all_units)) 

# pattern = r"""(?P<time>    # time group beginning 
#    (?P<value>[\d]+) # value of time unit 
#    \s*     # may or may not be space between digit and unit 
#    (?P<unit>%s)  # unit measurement of time 
#    \s*     # may or may not be space between digit and unit 
#   ) 
#   \w+""" % all_units 
pattern = r""".*(?P<time>  # time group beginning 
      (?P<value>[\d]+) # value of time unit 
      \s*     # may or may not be space between digit and unit 
      (?P<unit>%s)  # unit measurement of time 
      \s*     # may or may not be space between digit and unit 
      ).*     # may be words in between the times 
      """ % (all_units) 

regex = re.compile(pattern) 
for val in test_string: 
    match = regex.search(val) 
    print(match) 
    print(match.groupdict()) 

これが原因でないに無残に失敗しましたネストされたグループ化を適切に処理でき、グループの値を名前に割り当てることができません。

答えて

1

まず第一に、あなただけのコメントを複数行の正規表現を書いて、あなたがre.VERBOSEフラグを使用しない場合、それは何かと一致するように期待することはできません:あなたが言ったように

regex = re.compile(pattern, re.VERBOSE) 

を、最高の解決策はおそらくdictを使用することです

for val in test_string: 
    while True: #find all times 
     match = regex.search(val) #find the first unit 
     if not match: 
      break 
     matches= {} # keep track of all units and their values 
     while True: 
      matches[match.group('unit')]= int(match.group('value')) # add the match to the dict 
      val= val[match.end():] # remove part of the string so subsequent matches must start at index 0 
      m= regex.search(val) 
      if not m or m.start()!=0: # if there are no more matches or there's text between this match and the next, abort 
       break 
      match= m 
     print matches # the finished dict 

# output will be like {'h': 1, 'secs': 10, 'mins': 30} 

しかし、上記のコードはまだ動作しません。パターンが一致した間だけ任意のテキストを許可することはできません

  • :我々は2つの調整を行う必要があります。唯一の空白や単語を許可する「と」2試合の間、あなたは

    pattern = r"""(?P<time> # time group beginning (?P<value>[\d]+) # value of time unit \s* # may or may not be space between digit and unit (?P<unit>%s) # unit measurement of time \s* # may or may not be space between digit and unit (?:\band\s+)? # allow the word "and" between numbers ) # may be words in between the times """ % (all_units)

  • を使用することができますあなたがそうのようなあなたのユニットの順序を変更しました:

    year_units = ['years', 'year', 'y'] # yearS before year day_units = ['days', 'day', 'd'] # dayS before day, etc...

    なぜ?テキストが3 years and 1 dayの場合、3 years andの代わりに3 yearと一致するためです。

+0

ワウ!ありがとう、これは素晴らしいソリューションです!注文についての良い点は、あなたがそれを書いてしまうまで、それが「s」なしで一致することさえ私には起こりませんでした。 – chase

関連する問題