Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 22, 2012 15:15:15

Moroznui
От:
Зарегистрирован: 2010-10-12
Сообщения: 29
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

Нужно распарсить текстовый вид времени выполнения задачи в питоновское стандартное представление.
Сам не могу сходу написать регулярку и придумать алгоритм =( Мб кто-нибудь сталкивался с подобной задачей? гугление не помогло.

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

Написать полностью не прошу, просто наставьте на путь истинный. Должно же быть красивое решение.



Офлайн

#2 Дек. 22, 2012 16:16:39

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

Конкретизируйте Ваши чаяния, то чего Вы хотите сейчас, понять не представляется возможным. Набор слов. Выражайтесь яснее, не стесняйтесь дать сообществу Вашу задачу более ширше - какие входные данные, что надо получить?



Офлайн

#3 Дек. 22, 2012 16:59:42

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

Как вариант:

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)

Отредактировано reclosedev (Дек. 22, 2012 17:09:30)

Офлайн

#4 Дек. 22, 2012 17:04:34

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

reclosedev,
телепат 80-го левела!!!!!!!!!!
+1 восхищенье



Офлайн

#5 Дек. 22, 2012 17:16:44

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

FishHook
телепат 80-го левела!!!!!!!!!!
Ну не знаю Вроде понятный вопрос.

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

На самом деле
FishHook
какие входные данные,
Например, если из сплошного текста нужно timedelta выделить, мой вариант не подойдет.

Отредактировано reclosedev (Дек. 22, 2012 17:16:56)

Офлайн

#6 Дек. 24, 2012 06:25:35

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10015
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

>>> 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')
>>>
ещё



Офлайн

#7 Дек. 24, 2012 09:22:04

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

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))

Офлайн

#8 Дек. 24, 2012 12:30:34

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10015
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

reclosedev
только я бы их переименовал, чтобы с параметрами timedelta () совпадали
я так не делаю, потому что части остаются независимыми
сегодня оно используется для datetime, а завтра - для чего-нибудь совершенно другого

ещё появляется затенение: после того, как ты их связал, пропала ясность, и ты уже точно не знаешь, можно ли менять имена групп или это что-то нарушит



Отредактировано py.user.next (Дек. 24, 2012 12:34:21)

Офлайн

#9 Дек. 24, 2012 12:50:12

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

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

Офлайн

#10 Дек. 25, 2012 01:12:54

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10015
Репутация: +  857  -
Профиль   Отправить e-mail  

Парсинг "3d 5h 15m" в datetime.timedelta

reclosedev
Хотя, может быть явная передача mo.group('days', ‘hours’, ‘minutes’) выглядела бы более читаемой.
дело не в читаемости, у тебя одна часть кода зависит от другой
то есть у тебя названия групп не свободны, ты не можешь их поменять

reclosedev
Сомневаюсь что данный регексп будет использован за пределами одной функции
ты даже не думаешь, что он может прийти из внешнего файла, в котором нигде не будет написано, что имена групп должны соответствовать datetime



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version