子组上的Java正则表达式

时间:2018-09-02 10:49:03

标签: java regex date-parsing

关于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 :(得分:2)

    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位是正确的。用于日期的正确类是来自Java.time(现代Java日期和时间API)中的LocalDate。这是ISO日历系统中的日期,没有日期和时区。相比之下,Calendar表示某些日历系统中带有时区的日期和时间。远远超出您的需要。此外,Calendar类已经过时了,并且由于设计不佳而在四年半之前被java.time取代。

如果您确实需要Calendar对象来处理一些您无法更改或暂时不想更改的旧版API,请按以下方式进行转换:

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

如果不是美国/蓬塔阿雷纳斯,请替换正确的时区。

您的代码出了什么问题?

您的代码没有什么问题,除了它过于复杂并且使用过时的日期和时间类别。

    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

链接

Oracle tutorial: Date Time解释了如何使用java.time

答案 1 :(得分:0)

您的正则表达式没有问题(正如您提到的(\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));