【问题标题】:Standardize date string for datetime string为日期时间字符串标准化日期字符串
【发布时间】:2021-07-11 21:49:23
【问题描述】:

拜托,你能帮我解决这个问题吗?我已尝试实施以下解决方案,但均无效。

问题:

我必须将 CSV 文件中的所有字符串日期标准化为 YYYY-MM-DD HH: MM: SS:

2021-01-03 12:15:33.12365478 -> 2021-01-03 12:15:33 
2021-01-03 -> 2021-01-03 00:00:00

输入文件:

OP|VALUE1|VALUE2|DATE
I |123   | ABC  | 2021-01-03 12:15:33.12365478
I |123   | ABC  | 2021-01-03 12:15:21
I |123   | ABC  | 2021-01-03 12:15:12
I |123   | ABC  | 2021-01-03
I |123   | ABC  | 2021-01-03 12:15:33.12365478

希望输出文件:

OP|VALUE1|VALUE2|DATE
I |123   | ABC  | 2021-01-03 12:15:33
I |123   | ABC  | 2021-01-03 12:15:21
I |123   | ABC  | 2021-01-03 12:15:12
I |123   | ABC  | 2021-01-03 00:00:00
I |123   | ABC  | 2021-01-03 12:15:33

每个文件大小约为 104MB。 我想到的解决方案:

备选方案 1:

 public static String setDataCleaner(String in) {
        String stringFinal = "";
        
        for(String i: in.split("\\|")){
            
            if(i.matches("[0-9]{4}-[0-9]{2}-[0-9]{2}")) {
                stringFinal += i+" 00:00:00|";
            }else if(i.matches("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}.\\d+")) {
                stringFinal += i.substring(0,19)+"|";
            }else {
                stringFinal += i+"|";
            }
        }
        return(stringFinal);
    }

第一个替代方案很慢,因为 104MB 被“|”分割然后,这个拆分的每个部分都会根据正则表达式逐一检查!

第二种选择是:

public static String setDataCleaner(String in) {
    Pattern pattData1 = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}.\\d+");
    Pattern pattData2 = Pattern.compile("\\|[0-9]{4}-[0-9]{2}-[0-9]{2}\\|");

    String newString = "";
    Matcher matcher = pattData1.matcher(in);

    while (matcher.find()) {
        newString = in.substring(0, matcher.start()) + matcher.group().substring(0, 19)
                + in.substring(matcher.end());
    }

    matcher = pattData2.matcher(newString);
    String temp = "";

    while (matcher.find()) {
        temp = newString.substring(0, matcher.start());
        temp += matcher.group().substring(1, 11) + " 00:00:00|";
        temp += newString.substring(matcher.end());

    }
    return temp;
}

第二种选择看起来更好,但是,每次出现我的正则表达式匹配时都会覆盖 temp 变量,并且作为第一次尝试,它也很慢!

所以,我找不到一个简单的替代方法,例如,我可以执行 replaAll() 并同时使用 match valeu 的部分,如下所示:

String temp = "I|123|abc|2021-01-03 12:15:33.151615645"
tmp.replaceAll("<regexDateFormatt>", initialFoundDate+" 00:00:00")

String temp = "I|123|abc|2021-01-03 12:15:33"
tmp.replaceAll("<regexDateFormatt>", initialFoundDate.substring(0,19))

【问题讨论】:

  • 看看这个tutorial 来解析和格式化日期。
  • 如果 len = 10,追加" 00:00:00"。截断到 19 的最大 len。全部完成!

标签: java regex


【解决方案1】:

您可以在每行使用两次replaceAll(不使用split):

String res = line.replaceAll("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}).*$", "$1")
                 //remove everything after seconds
                 .replaceAll("(\\d{4}-\\d{2}-\\d{2})$", "$1 00:00:00");
                 //add 00:00:00 if time is not present

处理以下格式的最终​​版本:

I|2083|11111|false|1.53|2021-05-26 07:42:26.1263748559|2021-05-26.1263748559 
I|2030|22222|false|2.00|2021-05-26|2021-05-26


public static String setDataCleaner(String entrada) {
    return (entrada.replaceAll("((\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})\\.\\d*)", "$2")
                .replaceAll("\\|([0-9]{4}-[0-9]{2}-[0-9]{2})([\\|])", "|$1 00:00:00|")
                .replaceAll("\\|([0-9]{4}-[0-9]{2}-[0-9]{2})\r", "|$1 00:00:00"));
}

【讨论】:

  • 嗨@iota!我们就快到了!我的错并没有把我的案子的真实和完整的场景。这正是我所需要的,但是由于我之前的示例,一些正则表达式不匹配!你能帮忙考虑一下吗?我需要匹配以下场景:I|2083|11111|false|1.53|2021-05-26 07:42:26.1263748559|2021-05-26.1263748559 I|2030|22222|false|2.00|2021-05-26| 2021-05-26。正如你所看到的,我在“|”和我的字符串的 and 之间有毫秒和不完整的日期!
【解决方案2】:

我喜欢正则表达式,但这是我认为更简单的另一种观点。

public static void main (String[] args) throws ParseException {
    List<String> dates = List.of("2021-01-03 12:15:33.12365478", 
        "2021-01-03 12:15:21",
        "2021-01-03 12:15:12",
        "2021-01-03",
        "2021-01-03 12:15:33.12365478");
    
    for (String dateStr : dates) {
      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      dateFormat.setLenient(false);
      Date date = null;
      try {
        date = dateFormat.parse(dateStr);
      } catch (ParseException pe) {
        System.err.println("Wrong format: " + dateStr);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        date = df.parse(dateStr);
      }
      System.out.println(dateFormat.format(date));
    }
}

基本假设是您的大多数日期都符合yyyy-MM-dd HH:mm:ss 的通用格式,因此将通过直接转换。失败的案例将是那些没有时间组件的案例,您可以将它们作为例外情况处理。

最后,两种情况(常规和例外)都将被验证并转换为所需的日期格式字符串。

这是我的程序的输出:

2021-01-03 12:15:33
2021-01-03 12:15:21
2021-01-03 12:15:12
Wrong format: 2021-01-03
2021-01-03 00:00:00
2021-01-03 12:15:33

对于不一定精通正则表达式的开发人员,此解决方案更具可读性,因此也更易于维护。在做出此类决定时,不应忽视代码的可读性。

【讨论】:

  • 嗨@hfontanez 谢谢!所以,我想我需要一个不太复杂的场景。您的回答和想法令人难以置信,恭喜!但是,就我而言,除了我发现错误的模式之外,我还需要用相同的模式替换它,但要少一些字符或增加它们!我测试了 string.replaceAll() 并且看起来不错,但 i1m 卡在正则表达式中,因为我有以下模式: I|2083|11111|false|1.53|2021-05-26 07:42:26.1263748559|2021-05-26.1263748559 I| 2030|22222|false|2.00|2021-05-26|2021-05-26 正如你所看到的,我在“|”和我的行之间有毫秒和不完整的日期!
  • @FelipeCabral 将较大的问题分解为较小的问题。在你的情况下,每行中断可能会更好。然后找出日期列。如果日期总是在同一列中,那么您可以简单地提取该列(也许通过“|”再次拆分并使用数组索引来获取日期字符串。最后,将其传递给函数以转换日期。这就是你可以使用我的方法。建议的 REGEX 解决方案可能更好,但可能不可读,这是一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 2016-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多