简体   繁体   English

在Groovy中推断字符串值类型

[英]Inferring String value type in Groovy

I have a situation where I will be given a String and I need to determine what Class<?> best suits its value given the following constraints: 我有一种情况,我会得到一个字符串,我需要确定什么Class<?>最适合其值,给出以下约束:

  • If the String is (ignoring case) equal to "true" or "false" , it's a Boolean 如果String(忽略大小写)等于"true""false" ,则它是一个Boolean
  • Else, if the String is an integral number with no decimal point, it's an Integer 否则,如果String是一个没有小数点的Integer ,那么它就是一个Integer
  • Else, if the String is a number, it's a Double 否则,如果String是一个数字,那么它就是一个Double
  • Else, if the String matches the date time format YYYY-MM-DD hh:mm:ss.sss , then its a Java Date 否则,如果String匹配日期时间格式YYYY-MM-DD hh:mm:ss.sss ,那么它是一个Java Date
  • Else it's just a String afterall 否则它只是一个String毕竟

My best attempt is nasty and involves a lot of nested try/catch blocks: 我最好的尝试是讨厌的,涉及很多嵌套的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
}

Are there any Groovier ways of accomplishing this, perhaps something endemic to some obscure Groovy reflection API? 是否有任何Groovier方法来实现这一点,也许某些模糊的Groovy反射API特有的东西?

There are two methods which can help you in Groovy's extended String class (actually on CharSequence ): 在Groovy的扩展String类中有两种方法可以帮助你(实际上在CharSequence ):

But for other cases, AFAIK, you are on your own to implement the parsing. 但对于其他情况,AFAIK,您可以自己实现解析。 You could try working with a map and some closures, to reduce some boilerplate: 您可以尝试使用地图和一些闭包,以减少一些样板:

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

Note that if (Double) precedes (Integer) the tests won't work, since 9 is both a double and a integer. 请注意,如果(Double)(Integer) (Double)之前,则测试将不起作用,因为9既是double又是整数。

Groovy has a few features that would allow you to make this logic groovier. Groovy有一些功能可以让你使这个逻辑更加流畅。

  1. The powerful switch statement, which supports regexes and closures. 强大的switch语句,支持正则表达式和闭包。
  2. The isInteger and isDouble built-in CharSequence methods from the Groovy JDK. Groovy JDK中的isIntegerisDouble内置CharSequence方法。 Sadly, there's not a strict isBoolean so we'll need to implement that ourselves. 可悲的是,没有严格的isBoolean所以我们需要自己实现。
  3. The safe navigation operator to avoid NPEs. 安全导航操作员避免NPE。

Combining these features... 结合这些功能......

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

I used a regex instead of SimpleDateFormat to avoid having to catch an Exception. 我使用正则表达式而不是SimpleDateFormat来避免必须捕获异常。 It probably has slightly difference semantics, but you could alternatively create a helper method that returns false if there's an Exception thrown by Date.parse . 它可能具有稍微不同的语义,但您可以创建一个辅助方法,如果Date.parse抛出异常,则返回false。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM