如果字符串是Java中的正确格式,如何验证它

时间:2016-08-10 16:14:45

标签: java validation

我目前正在用Java编写验证方法,以检查字符串是否为几种不同的格式之一,以便更改为日期。

我希望它接受的格式如下:MM / DD / YY,M / DD / YY,MM / D / YY和M / D / YY。

我正在测试第一种格式,每当它告诉我即使我进入有效日期它也无效。

以下是我目前的代码:

public class IsDateFormatValid
{
   public boolean isValid(String date)
   {
      boolean result = true;
      if(date.length()>8||date.length()<6)
      {
         result= false;
      }
      if(date.length()==8)
      {
         if((Character.toString(date.charAt(2))!= "/")||(Character.toString(date.charAt(5))!="/"))
         {
            result=false;
         }   
      }
      if(date.length()==7)
      {
         if((Character.toString(date.charAt(2))!="/"&&Character.toString(date.charAt(1))!="/") ||(Character.toString(date.charAt(3))!="/"&&Character.toString(date.charAt(4))!= "/"))
         {
            result=false;
         }   
      }

      return result;   
   }
}   

我仍然需要为最后一个格式案例添加条件。我做了一个调试方法,发现总是返回false的部分是说:if((Character.toString(date.charAt(2))!=“/")||(Character.toString(date.charAt) (5))!= “/”))

这个问题的主要观点是尝试针对多种格式进行检查,而不仅仅是单一格式,这里的大多数其他问题都是如此。

4 个答案:

答案 0 :(得分:7)

您可能希望迭代可能的格式,例如:

实施例

private static String[] date_formats = {
        "yyyy-MM-dd",
        "yyyy/MM/dd",
        "dd/MM/yyyy",
        "dd-MM-yyyy",
        "yyyy MMM dd",
        "yyyy dd MMM",
        "dd MMM yyyy",
        "dd MMM yyyy"
};

/**
 * A brute-force workaround for Java's failure to accept "any arbitrary date format"
 */
public static Date tryDifferentFormats (String sDate) {
    Date myDate = null;
    for (String formatString : date_formats) {
        try {
            SimpleDateFormat format = new SimpleDateFormat(formatString);
            format.setLenient(false);
            myDate = format.parse(sDate);
            break;
        }
        catch (ParseException e) {
            // System.out.println("  fmt: " + formatString + ": FAIL");
        }
    }
    return myDate;
}

答案 1 :(得分:6)

一种可能很昂贵的简单方法;但不知何故,反对良好做法是这样的:

  1. 创建Formatter对象列表(每个允许的模式对应一个)。
  2. 迭代该列表;并尝试使用每个格式化程序解析日期字符串( lenient 设置为false!)。如果你得到一个不会抛出异常,你知道传入的字符串符合有效的格式。
  3. 要使用格式进行解析,您可以查看此question

    正如彼得指出的那样,这个解决方案并非线程安全。所以你需要调查那个question来处理它。

    另一方面,当像paulsm4那样建议时;你避免了线程问题...但不幸的是,你正在创建很多的格式化程序对象;之后你立即扔掉了。谈论浪费CPU周期和创建内存垃圾&#34;那里。

    选项2;更少&#34;昂贵&#34;是想出一个(或多个)正则表达式来匹配给定格式的字符串。但是,当然,它并不像苏珊娜所建议的那样容易;如你所知,你真的想拒绝像#34; 55/66/77&#34;它完全匹配一个简单的正则表达式,它只检查&#34;两个数字两个数字冲破两个数字&#34;。

    所以,是的,选项1很贵;所以这里的问题是:你的验证应该有多好?你想拒绝语法上的日期和#34;正确的#34;但那是&#34;语义上&#34;错了,比如&#34; 02/29/15&#34; (2015年不是闰年!)?!

    更新:考虑到这一点,一个很好的解决方案就像:

    1. 创建一个Map<Regex, String>,其值为一个字符串,可用作&#34;格式化程序输入&#34 ;;并且相应的密钥是&#34;匹配&#34;的正则表达式。格式
    2. 迭代地图键
    3. 如果没有关键匹配:完成;您知道您的输入格式未知/无效
    4. 如果密钥匹配:获取该密钥的映射值并使用它来创建非宽松格式化程序对象。现在您可以检查格式化程序是否可以解析您的输入。如果是这样:输入是您的一种格式的有效日期。

答案 2 :(得分:4)

尝试匹配正则表达式,它会减少你正在做的工作。

if(date.matches("\\d{1-2}\\\\d{1-2}\\\\d{1-2}")){
    // ..do something
}

答案 3 :(得分:0)

TL; DR

  1. 您的格式是(相同的)多种格式。
  2. 使用格式化程序来验证日期字符串是否有效。
    • 尤其要使用java.time中的DateTimeFormatter
  3. 请勿使用!=来比较字符串。

它们是相同格式的变体

除非我完全误解,否则格式的变化是月份可以是一位或两位数,月份中的一天可以是一位或两位数。我们可以将其作为一种单一格式进行处理。与其他两个答案一样,我认为对于大多数目的而言,最好对我们是否有有效的日期进行全面验证。不仅仅是数字位数和斜线位置的验证(正如Susannah Potts回答的那样,正则表达式可以做到)。因此,我们需要做的是:

  1. 定义格式程序
  2. 尝试解析;如果引发异常,则该字符串在您使用的任何格式变体中都不是有效的日期字符串。

1。定义格式器

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M/d/uu")
            .withResolverStyle(ResolverStyle.STRICT);

一个模式字母M将以一个或两位数字匹配月份数字。每月d类似。

首先让我们看看这一点。

    System.out.println(LocalDate.parse("12/28/66", dateFormatter));
    System.out.println(LocalDate.parse("11/06/37", dateFormatter));
    System.out.println(LocalDate.parse("11/2/58", dateFormatter));
    System.out.println(LocalDate.parse("03/14/35", dateFormatter));
    System.out.println(LocalDate.parse("05/04/68", dateFormatter));
    System.out.println(LocalDate.parse("09/3/06", dateFormatter));
    System.out.println(LocalDate.parse("5/23/99", dateFormatter));
    System.out.println(LocalDate.parse("1/06/00", dateFormatter));
    System.out.println(LocalDate.parse("2/8/76", dateFormatter));

输出为:

2066-12-28
2037-11-06
2058-11-02
2035-03-14
2068-05-04
2006-09-03
2099-05-23
2000-01-06
2076-02-08

2。尝试解析和捕获异常

    String dateString = "12/28/66";
    try {
        LocalDate.parse(dateString, dateFormatter);
        System.out.println(dateString + " is valid");
    } catch (DateTimeParseException dtpe) {
        System.out.println(dateString + " is not valid: " + dtpe.getMessage());
    }
12/28/66 is valid

尝试使用不遵循任何格式的日期字符串:

    String dateString = "ab/cd/ef";
ab/cd/ef is not valid: Text 'ab/cd/ef' could not be parsed at index 0

java.time

我建议使用java.time(现代Java日期和时间API)。一个答案中使用的DateSimpleDateFormat类的设计很差,而且已经过时了,后者特别麻烦。 java.time更好用。

您的代码出了什么问题?

有两个问题。

一个,正如您所说的,此if条件的总值为true,这会使您的result设置为false

         if((Character.toString(date.charAt(2))!= "/")||(Character.toString(date.charAt(5))!="/"))

将字符串与!=进行比较并不符合您的期望。这将测试两个字符串对象是否相同,而不是两个字符串是否相等。 Character.toString()将创建一个新的字符串对象,因此,它将始终是"/"之外的另一个对象。因此,即使来自Character.toString()的字符串也包含一个斜杠,!=的计算结果仍为true。

第二,您不能验证斜线之前,之间和之后的字符是否为数字。

链接