Как из строки времени (hh::mm::ss.SSS) вытащить минуты?

178
12 августа 2018, 15:50

Есть строки (их очень много) вида: String s1 = "10:11:23.555", т.е. формата hh::mm::ss.SSS. Нужно выделить минуты.
Пробовал так:

Pattern p = Pattern.compile("(\\:)(\\d+)(\\:)");
Matcher m = p.matcher(s1);
System.out.println(m.group());

Не помогло, возможно чего-то не понимаю.

Возможен другой подход: преобразовать исходную строку к какому-то формату Time, но на ходу не могу вспомнить подходящий класс.

Answer 1

Зачем использовать регулярное выражение для такой примитивной задачи?

String s1 = "10:11:23.555";
String[] tokens = s1.split(":");
String minutes = tokens[1];

UPDATE: Раз автор вопроса озабочен производительностью, а @MedvedevDev интересуется устройством String.split(), вопрос переходит в статус более-менее интересных, и я не могу не развернуть ответ.

Прежде всего надо заметить, что реализация методов стандартной библиотеки может отличаться в разных реализациях JVM или даже разных версиях одной и той же JVM. Причём метод может пробрасывать вызов в Сишный код, использующий SIMD-инструкции процессора, как это делает String.indexOf() например.

В Java 8 на HotSpot метод split, как правильно заметил @Nick, использует регулярные выражения только для аргумента из нескольких символов или содержащего мета-символы. Иначе положения разделителя перебираются в цикле с помощью уже упомянутого мной indexOf:

int off = 0;
int next = 0;
while ((next = indexOf(ch, off)) != -1) {
    list.add(substring(off, next));
    off = next + 1;
}

Посмотреть можно здесь.

Грешно было бы не проверить разницу в скорости между таким подходом и использованием регулярного выражения. Я набросал для этого тест JMH:

public class SplitBenchmark {
    @State(Scope.Benchmark)
    public static class BenchmarkState {
        public List<String> strings;
        public Pattern groupPattern;
        public Pattern splitPattern;
        @Setup(Level.Trial)
        public void setup() {
            groupPattern = Pattern.compile(":(\\d+):");
            splitPattern = Pattern.compile(":");
            Random random = new Random();
            strings = IntStream.rangeClosed(0, 100_000)
                               .mapToObj(x -> random.ints(0, 99)
                                                    .mapToObj(i -> String.format("%02d", i))
                                                    .limit(3)
                                                    .collect(Collectors.joining(":")))
                               .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
        }
    }
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void regexGroupMatching(BenchmarkState state, Blackhole blackhole) {
        for (int i = 0; i < state.strings.size(); i++) {
            String s = state.strings.get(i);
            Matcher m = state.groupPattern.matcher(s);
            if (m.find()) {
                String minutes = m.group(1);
                blackhole.consume(minutes);
            }
        }
    }
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void regexPatternSplit(BenchmarkState state, Blackhole blackhole) {
        for (int i = 0; i < state.strings.size(); i++) {
            String s = state.strings.get(i);
            String[] tokens = state.splitPattern.split(s);
            String minutes = tokens[1];
            blackhole.consume(minutes);
        }
    }
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void stringSplit(BenchmarkState state, Blackhole blackhole) {
        for (int i = 0; i < state.strings.size(); i++) {
            String s = state.strings.get(i);
            String[] tokens = s.split(":");
            String minutes = tokens[1];
            blackhole.consume(minutes);
        }
    }
}

Результат:

Benchmark                          Mode  Cnt   Score   Error  Units
SplitBenchmark.regexGroupMatching  avgt   25  10,382 ? 0,120  ms/op
SplitBenchmark.regexPatternSplit   avgt   25  17,235 ? 0,240  ms/op
SplitBenchmark.stringSplit         avgt   25   7,906 ? 0,069  ms/op

Как можно видеть, String.split() самый быстрый, а Pattern.split() существенно медленнее даже извлечения групп, чем я сам удивлён.

Answer 2

Чем не устроил метод substring?

String s1 = "10:11:23.555";
String minutes = s1.substring(3, 5);
System.out.println(minutes);
READ ALSO
Разница между CascadeType и ON DELETE/UPDATE операциями

Разница между CascadeType и ON DELETE/UPDATE операциями

Какая разница между Cascade types в Hibernate и ON DELETE/UPDATE actions в SQLНужно ли менять ON UPDATE/ON DELETE на Cascade для коректного использования CascadeType в Hibernate?

170
Привязка к полю

Привязка к полю

Есть такое оформление вывода выпадающего календаря:

193
fancybox галерея

fancybox галерея

Проблема с библиотекой fancybox до этого не работал с ней поэтому не могу понять в чем ошибка (при клике на ссылку происходит обычный переброс...

196