2016-07-16 5 views
2

기본 질문 :그룹과 중첩 된 정규식 (텍스트 파일에서 단위 변환)로 명명 그룹

어떻게 더 큰 정규식 그룹 내 다른 그룹의 가치와 중첩이있는 파이썬 정규식 그룹의 이름을 수 있습니까? 질문의

원산지 : '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} 

그러나 위 코드는 아직 작동하지 않습니다. 패턴이 일치하는 사이에 단지 어떤 텍스트를 허용 할 수 없습니다

  • : 우리는 두 가지 조정을 할 필요가있다. 공백 만 단어 "및"두 경기 사이에, 당신은

    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