Java Регулярное выражение в подгруппе - PullRequest
0 голосов
/ 02 сентября 2018

У меня следующий вопрос о регулярном выражении Java.

Когда я определяю регулярное выражение, используя шаблон:

String pattern = "(\\d{4})\\d{2}\\d{2}";

и входная строка "20180808", Я могу получить group(0) - 20180808
но

group(1) - не совпадает
group (2) - 08
group (3) - 08,

Я уверен, что регулярное выражение может быть эффективным в других языках, таких как Python, C #.

Может кто-нибудь помочь? спасибо за ваше экспертное решение.

@Test
public void testParseDateStringToMinimumOfTheDate() {
    try {
        UtilsFactory utilsFactory = UtilsFactory.getInstance();
        DateUtils dateUtils = utilsFactory.getInstanceOfDateUtils();
        CalendarUtils calendarUtils = utilsFactory.getInstanceOfCalendarUtils();
        calendarUtils.parseDateStringToMinimumOfTheDate("20180808");
    } catch (Exception e) {
        e.printStackTrace();
    }
} 

    public Calendar parseDateStringToMinimumOfTheDate(String dateString_yyyyMMdd) throws Exception {
    Calendar cal = null;
    String pattern = "(\\d{4})\\d{2}\\d{2}";
    try {
        cal = getMaxUtcCalendarToday();
        List<String> matchStringList = regMatch(dateString_yyyyMMdd, pattern);
        for (int i = 0; i < matchStringList.size(); i++) {

        }
    } catch (Exception e) {
        logger.error(getClassName() + ".parseDateStringToBeginningOfTheDate()- dateString_yyyyMMdd="
                + dateString_yyyyMMdd, e);
        throw e;
    }
    return cal;
}

private List<String> regMatch(String sourceString, String patternString) throws Exception {
    List<String> matchStrList = null;
    Pattern pattern = null;
    Matcher matcher = null;
    try {
        matchStrList = new ArrayList<String>();
        pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
        matcher = pattern.matcher(sourceString);
        while (matcher.find()) {
            matchStrList.add(matcher.group());
        }
    } catch (Exception e) {
        logger.error(
                getClassName() + ".regMatch() - sourceString=" + sourceString + ",patternString=" + patternString,
                e);
        throw e;
    }
    return matchStrList;
}

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018
    Pattern pattern = Pattern.compile("\\d{8}");
    String sourceString = "20180808";
    Matcher matcher = pattern.matcher(sourceString);
    while (matcher.find()) {
        LocalDate date = LocalDate.parse(matcher.group(), DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println(date);
    }

Выходные данные из этого фрагмента - ожидаемая дата:

2018-08-08

Если ваша строка может содержать больше текста, чем просто 8-значная дата, правильно использовать регулярное выражение для удаления этих 8-значных цифр. Правильный класс для даты - LocalDate из java.time, современного Java-API даты и времени. это дата в календарной системе ISO без времени суток и без часового пояса. Calendar, напротив, представляет дату и время с часовым поясом в некоторой календарной системе. Это гораздо больше, чем вам нужно. Также класс Calendar давно устарел и был заменен java.time четыре с половиной года назад, потому что он был плохо спроектирован.

Если вам нужен объект Calendar для какого-либо устаревшего API, который вы не можете изменить или не хотите изменять прямо сейчас, выполните преобразование следующим образом:

        ZoneId zone = ZoneId.of("America/Punta_Arenas");
        ZonedDateTime startOfDay = date.atStartOfDay(zone);
        Calendar cal = GregorianCalendar.from(startOfDay);

Пожалуйста, укажите правильный часовой пояс, если это не Америка / Punta_Arenas.

Что пошло не так в вашем коде?

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

    String patternString = "(\\d{4})(\\d{2})(\\d{2})";
    Pattern pattern = null;
    Matcher matcher = null;
    try {
        pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
        matcher = pattern.matcher(sourceString);
        while (matcher.find()) {
            System.out.println("group(1): " + matcher.group(1));
            System.out.println("group(2): " + matcher.group(2));
            System.out.println("group(3): " + matcher.group(3));
        }
    } catch (Exception e) {
        // TODO handle exception
        throw e;
    }

Вывод этого фрагмента:

group(1): 2018
group(2): 08
group(3): 08

Link

Учебное пособие по Oracle: Дата и время , объясняющее, как использовать java.time.

0 голосов
/ 02 сентября 2018

В вашем регулярном выражении нет ничего плохого (как вы упомянули (\d{4})(\d{2})(\d{2}). То, что вы делаете неправильно, , вы неправильно захватываете захваченную группу. Рефакторируйте свой метод для этого

private static List<String> regMatch(String sourceString, String patternString) {
      List<String> matchStrList = new ArrayList<>();

      Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
      Matcher matcher = pattern.matcher(sourceString);

      if(matcher.find()) {
          for(int i = 1; i <= matcher.groupCount(); i++) {
            matchStrList.add(matcher.group(i));
          }
      }

   return matchStrList;
}

Вы можете задаться вопросом, где находится group 0. Patter Захваченные API группы нумеруются путем подсчета открывающих скобок слева направо , а первая группа всегда представляет собой целое регулярное выражение. Таким образом, для строки (A)(B(C)) Вы получите группы, как показано ниже

Group 0: (A)(B(C))
Group 1: (A)
Group 2: (B(C))
Group 3: (C)

А метод groupCount() возвращает количество групп захвата, присутствующих в шаблоне сопоставителя.

Примечание на стороне

Как уже упоминалось в комментарии @ haba713, вы, возможно, не захотите делать все эти регулярные выражения, просто анализируя Date. Вы можете просто использовать SimpleDateFormat для этого.

SimpleDateFormat formater = new SimpleDateFormat("yyyyMMdd");
System.out.println(formater.parse(dateString));
...