Найти - Пользователи
Полная версия: Парсинг "3d 5h 15m" в datetime.timedelta
Начало » Python для новичков » Парсинг "3d 5h 15m" в datetime.timedelta
1
Moroznui
Нужно распарсить текстовый вид времени выполнения задачи в питоновское стандартное представление.
Сам не могу сходу написать регулярку и придумать алгоритм =( Мб кто-нибудь сталкивался с подобной задачей? гугление не помогло.

Все осложняется тем, что могут быть разные сложные варианты:
23d 5m
6h
25h 150m
и т.д.

Написать полностью не прошу, просто наставьте на путь истинный. Должно же быть красивое решение.
FishHook
Конкретизируйте Ваши чаяния, то чего Вы хотите сейчас, понять не представляется возможным. Набор слов. Выражайтесь яснее, не стесняйтесь дать сообществу Вашу задачу более ширше - какие входные данные, что надо получить?
reclosedev
Как вариант:
import re
import datetime
 
 
_td_names = [
    'days',
    'hours',
    'minutes',
    'seconds',
]
td_regexps = {name : re.compile(r"(\d+)%s" % name[0]) for name in _td_names}
 
def parse_timedelta(text):
    fields = {}
    for name, pattern in td_regexps.items():
        m = pattern.search(text)
        if m:
            fields[name] = float(m.group(1))
    if not fields:
        return None  # or raise exception
    return datetime.timedelta(**fields)
 
test_strings = [
    "3d 5h 15m",
    "23d 5m",
    "6h",
    "25h 150m",
    "aasdf",
]
for text in test_strings:
    print parse_timedelta(text)
Вариант 2
import re
import datetime
 
 
_td_names = {
    'd': 'days',
    'h': 'hours',
    'm': 'minutes',
    's': 'seconds'
}
td_regexp = re.compile(r"\b(\d+)(%s)\b" % '|'.join(_td_names.keys()))
 
def parse_timedelta(text):
    fields = {}
    for value, name in td_regexp.findall(text):
        fields[_td_names[name]] = float(value)
    if not fields:
        return None
    return datetime.timedelta(**fields)
 
test_strings = [
    "3d 5h 15m",
    "23d 5m",
    "6h",
    "25h 150m",
    "aasdf",
]
for text in test_strings:
    print parse_timedelta(text)
FishHook
reclosedev,
телепат 80-го левела!!!!!!!!!!
+1 восхищенье
reclosedev
FishHook
телепат 80-го левела!!!!!!!!!!
Ну не знаю Вроде понятный вопрос.

Кстати в гугле тоже много вариантов https://www.google.ru/search?q=python+parse+timedelta
Но универсальный парсер, который предусмотрел бы все возможные типы написания, будет сложно сделать.

На самом деле
FishHook
какие входные данные,
Например, если из сплошного текста нужно timedelta выделить, мой вариант не подойдет.
py.user.next
>>> import re
>>> 
>>> s = """
... 23d 5m
... 6h
... 25h 150m
... 3d 5h 15m
... 23d 5m
... 6h
... 25h 150m
... aasdf
... """
>>> 
>>> pat = re.compile(r'((?P<day>\d+)d)?((?P<hour>\d+)h)?((?P<min>\d+)m)?')
>>> 
>>> for line in s.splitlines():
...     mo = pat.match(line.replace(' ', ''))
...     if mo is not None and mo.group(0):
...         print(mo.group('day', 'hour', 'min'))
... 
('23', None, '5')
(None, '6', None)
(None, '25', '150')
('3', '5', '15')
('23', None, '5')
(None, '6', None)
(None, '25', '150')
>>>
ещё
reclosedev
py.user.next
Хороший вариант с именованными группами, только я бы их переименовал, чтобы с параметрами timedelta () совпадали.
pat = re.compile(r'((?P<days>\d+)d)?((?P<hours>\d+)h)?((?P<minutes>\d+)m)?')
for line in s.splitlines():
    mo = pat.match(line.replace(' ', ''))
    if mo is not None and mo.group(0):
        fields = {name: int(value)
                  for name, value in mo.groupdict().items()
                  if value is not None}
        print(datetime.timedelta(**fields))
py.user.next
reclosedev
только я бы их переименовал, чтобы с параметрами timedelta () совпадали
я так не делаю, потому что части остаются независимыми
сегодня оно используется для datetime, а завтра - для чего-нибудь совершенно другого

ещё появляется затенение: после того, как ты их связал, пропала ясность, и ты уже точно не знаешь, можно ли менять имена групп или это что-то нарушит
reclosedev
py.user.next
Звучит надуманно. Сомневаюсь что данный регексп будет использован за пределами одной функции, предназначение которой - парсинг timedelta. Хотя, может быть явная передача mo.group('days', ‘hours’, ‘minutes’) выглядела бы более читаемой.
py.user.next
reclosedev
Хотя, может быть явная передача mo.group('days', ‘hours’, ‘minutes’) выглядела бы более читаемой.
дело не в читаемости, у тебя одна часть кода зависит от другой
то есть у тебя названия групп не свободны, ты не можешь их поменять

reclosedev
Сомневаюсь что данный регексп будет использован за пределами одной функции
ты даже не думаешь, что он может прийти из внешнего файла, в котором нигде не будет написано, что имена групп должны соответствовать datetime
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB