【问题标题】:Inferring String value type in Groovy在 Groovy 中推断字符串值类型
【发布时间】:2016-11-30 12:19:13
【问题描述】:

我有一种情况,我将获得一个字符串,我需要根据以下限制确定最适合其值的 Class<?>

  • 如果字符串(忽略大小写)等于"true""false",则为Boolean
  • 否则,如果字符串是没有小数点的整数,则为Integer
  • 否则,如果字符串是数字,则为Double
  • 否则,如果字符串匹配日期时间格式YYYY-MM-DD hh:mm:ss.sss,那么它是Java Date
  • 否则它只是 String 毕竟

我最好的尝试是讨厌的,涉及很多嵌套的try/catch 块:

// Groovy pseudo-code
Class<?> determineValueType(String value) {
    Class<?> clazz
    if(value.equalsIgnoreCase('true') || value.equalsIgnoreCase('false')) {
        clazz = Boolean
    } else {
        try {
            Integer.parse(value)
            clazz = Integer
        } catch(Exception ex1) {
            try {
                Double.parse(value)
                clazz = Double
            } catch(Exception ex2) {
                try {
                    Date.parse('YYYY-MM-DD hh:mm:ss.sss', value)
                    clazz = Date
                } catch(Exception ex3) {
                    clazz = String
                }
            }
        }
    }

    clazz
}

是否有任何 Groovier 方法可以实现这一点,也许是某些晦涩的 Groovy 反射 API 特有的方法?

【问题讨论】:

    标签: java date reflection groovy introspection


    【解决方案1】:

    在 Groovy 的扩展 String 类(实际上是在 CharSequence)中有两种方法可以帮助您:

    但对于其他情况,AFAIK,您需要自己实现解析。您可以尝试使用地图和一些闭包,以减少一些样板:

    Class parse(val) {
        def convert = [
            (Integer) : { it.toInteger() },
            (Double)  : { it.toDouble() },
            (Date)    : { Date.parse('YYYY-MM-DD hh:mm:ss.sss', it) },
            (Boolean) : { Boolean.parseBoolean it },
            (String)  : { it }
        ]
    
        convert.findResult { key, value ->
            try {
                if (value(val)) return key
            } catch (e) {}
        }
    }
    
    assert parse('9.1') == Double
    assert parse('9') == Integer
    assert parse('1985-10-26 01:22:00.000') == Date // great scott!
    assert parse('chicken') == String
    assert parse('True') == Boolean
    

    请注意,如果 (Double)(Integer) 之前,则测试将不起作用,因为 9 既是双精度数又是整数。

    【讨论】:

      【解决方案2】:

      Groovy 有一些功能可以让您使这个逻辑更时髦。

      1. 强大的switch 语句,支持正则表达式和闭包。
      2. Groovy JDK 中的 isIntegerisDouble 内置 CharSequence 方法。遗憾的是,没有严格的 isBoolean,所以我们需要自己实现。
      3. safe navigation operator 可避免 NPE。

      结合这些功能...

      Class<?> determineValueType(String value) {
          switch (value) {
              case { ['true', 'false'].contains(value?.toLowerCase()) }: 
                  return Boolean
              case { value?.isInteger() }: 
                  return Integer
              case { value?.isDouble() }: 
                  return Double
              case ~/^\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}\.\d{3}$/: 
                  return Date
              default: 
                  return String
          }
      }
      
      assert determineValueType('true') == Boolean
      assert determineValueType('false') == Boolean
      assert determineValueType('2039230') == Integer
      assert determineValueType('203923.0') == Double
      assert determineValueType('2016-07-26 12:00:00.000') == Date
      assert determineValueType('foo') == String
      

      我使用正则表达式而不是 SimpleDateFormat 来避免捕获异常。它的语义可能略有不同,但您也可以创建一个辅助方法,如果 Date.parse 抛出异常,则返回 false。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-17
        • 2017-05-13
        • 2017-08-24
        • 1970-01-01
        • 2019-03-26
        • 2014-01-21
        相关资源
        最近更新 更多