001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.util;
015
016import java.time.format.DateTimeFormatter;
017import java.util.ArrayList;
018import java.util.List;
019import java.util.Locale;
020
021/**
022 * This class is concerned with computing a regex corresponding to a date
023 * pattern (in {@link DateTimeFormatter} format).
024 *
025 * @author Ceki Gülcü
026 */
027public class DatePatternToRegexUtil {
028
029    final String datePattern;
030    final int datePatternLength;
031    final CharSequenceToRegexMapper regexMapper;
032
033    /**
034     * Create an instance using the symbols of the default locale.
035     *
036     * @param datePattern date pattern in {@link DateTimeFormatter} format
037     */
038    public DatePatternToRegexUtil(String datePattern) {
039        this(datePattern, Locale.getDefault(Locale.Category.FORMAT));
040    }
041
042    /**
043     * Create an instance using the symbols of the given locale.
044     *
045     * @param datePattern date pattern in {@link DateTimeFormatter} format
046     * @param locale      the locale whose month, weekday and am/pm symbols are used
047     * @since 1.7.0
048     */
049    public DatePatternToRegexUtil(String datePattern, Locale locale) {
050        this.datePattern = datePattern;
051        datePatternLength = datePattern.length();
052        regexMapper = new CharSequenceToRegexMapper(locale);
053    }
054
055    public String toRegex() {
056        List<CharSequenceState> charSequenceList = tokenize();
057        StringBuilder sb = new StringBuilder();
058        for (CharSequenceState seq : charSequenceList) {
059            sb.append(regexMapper.toRegex(seq));
060        }
061        return sb.toString();
062    }
063
064    private List<CharSequenceState> tokenize() {
065        List<CharSequenceState> sequenceList = new ArrayList<CharSequenceState>();
066
067        CharSequenceState lastCharSequenceState = null;
068
069        for (int i = 0; i < datePatternLength; i++) {
070            char t = datePattern.charAt(i);
071            if (lastCharSequenceState == null || lastCharSequenceState.c != t) {
072                lastCharSequenceState = new CharSequenceState(t);
073                sequenceList.add(lastCharSequenceState);
074            } else {
075                lastCharSequenceState.incrementOccurrences();
076            }
077        }
078        return sequenceList;
079    }
080}