Получение времени из строки
Возможно ли реализовать такую штуку: есть строка. В ней может быть написано 1year/1month/1week/1day/1hour/1minute/1second или несколько вместе. Например: 1week5day. И мы должны получить время в миллисекундах, которое занимает данный промежуток времени. Если возможно, то подтолкните, а то я сам не догоняю.
Ответы (2 шт):
Сложную задачу нужно делить по частям:
- Парсинг текста. Для получения количества и единицы измерения времени (
year,month, ...). Мне кажется, в вашем случае, самое удобное это через регулярные выражения. - Сопоставление единицы измерения времени к количеству миллисекунд
- Суммирование миллисекунд
Покажу примеры шагов, но с неполной реализацией
Тут в регулярном выражении я указываю, что ожидается число и единица измерения (остальные сами добавите, разделяя их вертикальной чертой)
String text = "1week5day10hour"; Matcher m = Pattern.compile("(\\d+)(week|day|hour)").matcher(text); while (m.find()) { int number = Integer.parseInt(m.group(1)); String kind = m.group(2); System.out.println(number + " " + kind); }Результатом будет:
1 week 5 day 10 hourМожно это сделать через
if/switch, но я сделаю через словарь. Кст, в этом случае удобно сделать регулярное выражение от ключей словаря, чтобы не повторяться в словаре и в шаблоне регулярки.Map<String, Long> kindByMs = new HashMap<String, Long>() {{ put("week", 604800000L); put("day", 86400000L); put("hour", 3600000L); }}; Matcher m = <регулярка> while (m.find()) { int number = Integer.parseInt(m.group(1)); String kind = m.group(2); long ms = kindByMs.get(kind); System.out.println(kind + " = " + ms + " ms"); }Результат:
week = 604800000 ms day = 86400000 ms hour = 3600000 msДля сложения используйте переменную с типом
long, но, возможно, лучше через большие числа, т.е. через BigInteger
Можно еще при помощи сканера, стримов и таймюнитов (последнее для упрощения конвертации):
public static void main(String[] args) {
Scanner scanner = new Scanner("1hour10minute");
System.out.println(
scanner
.findAll("(\\d+)(second|minute|hour|day|week|month|year)")
.map(matchResult ->
Long
.valueOf(TimeUnit.valueOf((matchResult.group(2) + "s")
.toUpperCase())
.toMillis(Integer.valueOf(matchResult.group(1))))
).reduce((aLong, aLong2) -> aLong + aLong2).orElse(0L)
);
}
Что тут происходит?
findAllразбивает строку на токены "число-период" и приводит всё это к стриму.mapприводит каждый элемент стрима к миллисекундам. Для этого он использует стандартную сущностьTimeUnit. Т.к. таймюниты из задачи отличаются от нужного представления только единственным числом, мы просто добавляемsв конец.reduceсхлопывает наш стрим в число через сложение отдельных элементов.