22

ISO 8601興味のために、動画の長さを YouTubeから秒に変換したいと思います。私のソリューションを将来証明するために、非常に長いビデオを選んでテストしました。

API は、その期間中これを提供します -"duration": "P1W2DT6H21M32S"

stackoverflow.com/questions/969285dateutilで提案されているように、この期間を解析してみました。

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

これは例外をスローします

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

私は何が欠けていますか?

4

8 に答える 8

35

Python の組み込みの dateutil モジュールは、ISO 8601 の期間ではなく、ISO 8601 の日付の解析のみをサポートします。そのためには、「isodate」ライブラリを使用できます ( https://pypi.python.org/pypi/isodateの pypi で-- pip または easy_install を使用してインストールします)。このライブラリは、ISO 8601 期間を完全にサポートしており、datetime.timedelta オブジェクトに変換します。したがって、ライブラリをインポートしたら、次のように簡単です。

import isodate
dur = isodate.parse_duration('P1W2DT6H21M32S')
print(dur.total_seconds())
于 2013-05-24T20:48:33.447 に答える
6

9000の正規表現ソリューション (ありがとうございます - 正規表現の驚くべき熟達!) を使用して、元の投稿者の YouTube ユース ケース、つまり時間、分、秒を秒に変換する作業を完了する私の答えを次に示します。.groups()の代わりにを使用し.groupdict()、その後に愛情を込めて構築されたリスト内包表記をいくつか使用しました。

import re

def yt_time(duration="P1W2DT6H21M32S"):
    """
    Converts YouTube duration (ISO 8061)
    into Seconds

    see http://en.wikipedia.org/wiki/ISO_8601#Durations
    """
    ISO_8601 = 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)?'   # hours
        '(?:(?P<minutes>\d+)M)?' # minutes
        '(?:(?P<seconds>\d+)S)?' # seconds
        ')?')   # end of time part
    # Convert regex matches into a short list of time units
    units = list(ISO_8601.match(duration).groups()[-3:])
    # Put list in ascending order & remove 'None' types
    units = list(reversed([int(x) if x != None else 0 for x in units]))
    # Do the maths
    return sum([x*60**units.index(x) for x in units])

上位に投稿できなくて申し訳ありません - ここはまだ新しく、コメントを追加するのに十分な評価ポイントがありません。

于 2018-04-23T08:43:31.660 に答える
4

1週間2日6時間21分32秒の動画じゃないですか?

Youtube では 222 時間 21 分 17 秒と表示されています。1 * 7 * 24 + 2 * 24 + 6 = 222 ですが、17 秒と 32 秒の不一致がどこから来るのかわかりません。丸め誤差の可能性もあります。

私の考えでは、そのためのパーサーを書くことはそれほど難しくありません。残念ながらdateutil、間隔を解析するようには見えず、日時ポイントのみを解析します。

アップデート:

このためのパッケージがあるようですが、正規表現の力、簡潔さ、および理解できない構文の例として、ここにパーサーを示します。

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}

ここでは、これらのデータから正確な秒数を意図的に計算していません。些細なことに見えますが (上記参照)、実際にはそうではありません。たとえば、1 月 1 日から 2 か月の距離は、年によって 58 日 (30+28) または 59 (30+29) ですが、3 月 1 日からは常に 61 日です。適切なカレンダーの実装では、これらすべてを考慮に入れる必要があります。Youtube クリップの長さを計算するには、長すぎる必要があります。

于 2013-05-24T19:59:19.677 に答える
1

これが私が思いついたものです - 時間を解釈するためのカスタムパーサー:

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

今ではおそらく超非クールなどですが、機能するので、あなたのことを気にかけているので共有しています.

于 2013-05-24T20:31:52.090 に答える