Задать вопрос

Как парсить единицы измерения ms/s на pyparsing и python?

Есть строки: "1m57s", "17s520ms", "1m", "10s", "200ms" и так далее. Надо распарсить с помощью pyparsing в минусы, секунды и миллисекунды.

minutes = ( Word(nums, max=8) + Suppress(Literal("m")) + Suppress(CharsNotIn("s") or Empty()) ) ('minutes')
seconds = ( Word(nums, max=8) + Suppress(Literal("s")) ) ('seconds')
mseconds = ( Word(nums, max=8) + Suppress(Literal("ms")) ) ('mseconds')
пытался сделать так, но либо не ловятся строки вида "1m", либо на строке 400ms ловится первая часть(400m) и ошибочно принимается за минуты.

Вот код для проверки:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from pyparsing import *

strings = {"1m57s", "17s520ms", "1m", "10s", "200ms"}

def parse_second(string):
  minutes = ( Word(nums, max=8) + Suppress(Literal("m")) + (Suppress(CharsNotIn("s") or Empty())) ) ('minutes')
  seconds = ( Word(nums, max=8) + Suppress(Literal("s")) ) ('seconds')
  time_minutes = minutes
  time_seconds = seconds
  string = string.rstrip()
  minutes_count = 0
  seconds_count = 0

  try:
    parsed_time_minutes = time_minutes.parseString(string)
    if (parsed_time_minutes.minutes != ""):
      minutes_count = int(parsed_time_minutes.minutes.asList()[0])
  except BaseException:
    pass

  try:
    parsed_time_seconds = time_seconds.parseString(string)
    if (parsed_time_seconds.seconds != ""):
      seconds_count = int(parsed_time_seconds.seconds.asList()[0])
  except BaseException:
    pass

  all_sec = (minutes_count*60) + seconds_count
  return all_sec

def parse():
  for element in strings:
    result = parse_second(element)
    print(element, result)

parse()


Результат работы:

('1m57s', 60) ✗ Неправильно, должен быть 60+57=117
('10s', 10) ✓ Правильно
('1m', 0) ✗ Неправильно, должен быть 60
('17s520ms', 17) ✓ Правильно, целых секунд — 17
('200ms', 0) ✓ Правильно, целых секунд — ноль
  • Вопрос задан
  • 226 просмотров
Подписаться 2 Простой 5 комментариев
Пригласить эксперта
Ответы на вопрос 2
на бросал быстренько на чистой регулярки, дальше че хотите то и делайте с результатами
import re
from dataclasses import dataclass


@dataclass
class Time:
    minute: int
    second: int
    ms: int

    @classmethod
    def init(cls, data):
        return cls(**{k: int(v) for k, v in data.items()})

    def to_seconds(self):
        return self.minute * 60 + self.second


strings = ["1m57s", "17s520ms", "1m", "10s"]
time_parse = re.compile(r"((?P<minute>\d+)(m(?!s)))?((?P<second>\d+)(s))?((?P<ms>\d+)(ms))?")

d = [Time.init(time_parse.match(v).groupdict(default='0')) for v in strings]

print(d)
print([v.to_seconds() for v in d])

[Time(minute=1, second=57, ms=0), Time(minute=0, second=17, ms=520), Time(minute=1, second=0, ms=0), Time(minute=0, second=10, ms=0)]
[117, 17, 60, 10]
Ответ написан
@Filart97
в первой строке приоритет у операции "or" выше чем у "+", по идее, попробуй в скобки взять последнюю операцию
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы