2013-05-24 6 views
6

관심을 끌기 위해 YouTubes ISO 8601의 비디오 재생 시간을 초로 변환하고 싶습니다. 나중에 내 솔루션을 증명하기 위해 나는 그것을 테스트하기 위해 a really long video을 골랐다. "duration": "P1W2DT6H21M32S"YouTube API 재생 시간을 초 단위로 변환하는 방법은 무엇입니까?

내가 stackoverflow.com/questions/969285에 제안 dateutil이 지속 시간을 분석하는 시도 -

는 API이이 기간 동안 제공한다.

import dateutil.parser 
duration = = dateutil.parser.parse('P1W2DT6H21M32S') 

이 내가 무엇을 놓치고 예외

TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' 

을 던져?

답변

13

파이썬의 내장 dateutil 모듈은 ISO 8601 기간이 아닌 ISO 8601 날짜의 구문 분석 만 지원합니다. 이를 위해 "isodate"라이브러리 (https://pypi.python.org/pypi/isodate - pip 또는 easy_install을 통해 설치)에서 라이브러리를 사용할 수 있습니다. 이 라이브러리는 ISO 8601 기간을 완벽하게 지원하여 datetime.timedelta 객체로 변환합니다. 2.7 이상 파이썬에

dur=isodate.parse_duration('P1W2DT6H21M32S') 
print dur.total_seconds() 
+0

와우, 내 파서를 작성했다고 생각하면이 모든 것이 너무 쉽게 보이게됩니다 :) 감사합니다! –

+0

@MorganWilde Python의 가장 큰 장점 중 하나는 표준 라이브러리가 아니라면 pypi에 기존 솔루션을 찾을 수 있다는 것입니다. 솔루션이 이미 존재하는 경우 (파이썬뿐만 아니라 모든 언어로) 구현을 피하기 위해 노력하는 것이 좋습니다. – zstewart

1

동영상은 1 주일, 2 일, 6 시간 21 분 32 초가 아닌가요?

Youtube에 따르면 222 시간 21 분 17 초, 1 * 7 * 24 + 2 * 24 + 6 = 222. 나는 17 초와 32 초의 불일치가 어디에서 유래했는지 모른다. 반올림 오류가있을 수 있습니다.

내 생각에, 파서 작성은 그리 어렵지 않습니다. 불행히도 dateutil은 간격을 파싱하지 않는 것으로 보입니다. datetime 포인트 만 해석합니다.

업데이트 :

import re 

# see http://en.wikipedia.org/wiki/ISO_8601#Durations 
ISO_8601_period_rx = re.compile(
    'P' # designates a period 
    '(?:(?P<years>\d+)Y)?' # years 
    '(?:(?P<months>\d+)M)?' # months 
    '(?:(?P<weeks>\d+)W)?' # weeks 
    '(?:(?P<days>\d+)D)?' # days 
    '(?:T' # time part must begin with a T 
    '(?:(?P<hours>\d+)H)?' # hourss 
    '(?:(?P<minutes>\d+)M)?' # minutes 
    '(?:(?P<seconds>\d+)S)?' # seconds 
    ')?' # end of time part 
) 


from pprint import pprint 
pprint(ISO_8601_period_rx.match('P1W2DT6H21M32S').groupdict()) 

# {'days': '2', 
# 'hours': '6', 
# 'minutes': '21', 
# 'months': None, 
# 'seconds': '32', 
# 'weeks': '1', 
# 'years': None} 

I : 나는 그러나 다만 정규 표현식 전력, 간결하고 이해할 수없는 구문의 예로서,이에 대한 패키지가 있음을 볼 수

, 여기 당신을위한 파서이다 의도적으로이 데이터에서 정확한 초 수를 계산하지 않습니다. 그것은 사소한 것처럼 보이지만 (위 참조) 정말로 그렇지 않습니다. 예를 들어, 1 월 1 일부터 2 개월의 거리는 연도에 따라 58 일 (30 + 28) 또는 59 일 (30 + 29)이며, 3 월 1 일부터는 항상 61 일입니다. 적절한 달력 구현은이 모든 것을 고려해야합니다. Youtube 클립 길이 계산의 경우 초과해야합니다.

+0

는 그 내 솔루션이 얼마나 끔찍한 확인 지금까지 :) –

+0

최고의 솔루션 것 같다 ... : D 간결은 가장 확실하게 내 기지 ... –

+0

@MorganWilde 탈출 : 음,에 내 체크 아웃을 업데이트 된 답변. 나는 항상 유한 오토 마타를 작성하지는 않지만, 할 때 잘 알려진 도메인 특정 언어를 사용하려고합니다. – 9000

0

그래서 이것이 내가 생각 해낸 것입니다 - 시간을 해석하는 사용자 정의 파서 : 지금은 아마 그래서 슈퍼 비 시원하고

def durationToSeconds(duration): 
    """ 
    duration - ISO 8601 time format 
    examples : 
     'P1W2DT6H21M32S' - 1 week, 2 days, 6 hours, 21 mins, 32 secs, 
     'PT7M15S' - 7 mins, 15 secs 
    """ 
    split = duration.split('T') 
    period = split[0] 
    time = split[1] 
    timeD = {} 

    # days & weeks 
    if len(period) > 1: 
     timeD['days'] = int(period[-2:-1]) 
    if len(period) > 3: 
     timeD['weeks'] = int(period[:-3].replace('P', '')) 

    # hours, minutes & seconds 
    if len(time.split('H')) > 1: 
     timeD['hours'] = int(time.split('H')[0]) 
     time = time.split('H')[1] 
    if len(time.split('M')) > 1: 
     timeD['minutes'] = int(time.split('M')[0]) 
     time = time.split('M')[1]  
    if len(time.split('S')) > 1: 
     timeD['seconds'] = int(time.split('S')[0]) 

    # convert to seconds 
    timeS = timeD.get('weeks', 0) * (7*24*60*60) + \ 
      timeD.get('days', 0) * (24*60*60) + \ 
      timeD.get('hours', 0) * (60*60) + \ 
      timeD.get('minutes', 0) * (60) + \ 
      timeD.get('seconds', 0) 

    return timeS 

을하지만, 작동, 그래서 때문에 공유 해요 나는 너를 걱정한다.

4

작품 : 라이브러리를 가져온 한 번 그래서, 그것만큼 간단합니다. JavaScript one-liner for Youtube v3 question here에서 채택되었습니다.

import re 

def YTDurationToSeconds(duration): 
    match = re.match('PT(\d+H)?(\d+M)?(\d+S)?', duration).groups() 
    hours = _js_parseInt(match[0]) if match[0] else 0 
    minutes = _js_parseInt(match[1]) if match[1] else 0 
    seconds = _js_parseInt(match[2]) if match[2] else 0 
    return hours * 3600 + minutes * 60 + seconds 

# js-like parseInt 
# https://gist.github.com/douglasmiranda/2174255 
def _js_parseInt(string): 
    return int(''.join([x for x in string if x.isdigit()])) 

# example output 
YTDurationToSeconds(u'PT15M33S') 
# 933 

는 유튜브 문자열은 수학적하지, 추가 (시간

이 문자가 숫자 인 경우, 한 번에 입력 문자열 1 문자를 구문 분석하는 방식으로 작동합니다
1

단순히 추가합니다까지 사용 범위 iso8061 기간 형식을 처리합니다 add)를 파싱중인 현재 값에 추가합니다. 'wdhms'중 하나 인 경우 현재 값이 적절한 변수 (주, 일,시, 분, 초)에 할당되고 값은 재설정되어 다음 값을 취할 준비가됩니다. 마지막으로 5 개의 구문 분석 된 값에서 초를 합계합니다.

def ytDurationToSeconds(duration): #eg P1W2DT6H21M32S 
    week = 0 
    day = 0 
    hour = 0 
    min = 0 
    sec = 0 

    duration = duration.lower() 

    value = '' 
    for c in duration: 
     if c.isdigit(): 
      value += c 
      continue 

     elif c == 'p': 
      pass 
     elif c == 't': 
      pass 
     elif c == 'w': 
      week = int(value) * 604800 
     elif c == 'd': 
      day = int(value) * 86400 
     elif c == 'h': 
      hour = int(value) * 3600 
     elif c == 'm': 
      min = int(value) * 60 
     elif c == 's': 
      sec = int(value) 

     value = '' 

    return week + day + hour + min + sec 
관련 문제