推断 Groovy 中的字符串值类型
Inferring String value type in Groovy
我有一种情况,我将得到一个字符串,我需要确定什么 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 所特有的东西?
在 Groovy 的扩展 String class(实际上在 CharSequence
中)有两种方法可以帮助您:
但对于其他情况,据我所知,您需要自己实施解析。您可以尝试使用地图和一些闭包来减少一些样板文件:
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
既是双精度又是整数。
Groovy 有一些功能可以让您使这个逻辑更时髦。
- 强大的switch语句,支持正则表达式和闭包。
isInteger
和 isDouble
来自 Groovy JDK 的内置 CharSequence 方法。遗憾的是,没有严格的 isBoolean
所以我们需要自己实施。
- 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
.
抛出异常,则 returns false
我有一种情况,我将得到一个字符串,我需要确定什么 Class<?>
最适合它的值,给定以下限制:
- 如果字符串(忽略大小写)等于
"true"
或"false"
,则它是Boolean
- 否则,如果字符串是一个没有小数点的整数,它是一个
Integer
- 否则,如果字符串是数字,则为
Double
- 否则,如果字符串匹配日期时间格式
YYYY-MM-DD hh:mm:ss.sss
,则它是 JavaDate
- 否则它只是
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 所特有的东西?
在 Groovy 的扩展 String class(实际上在 CharSequence
中)有两种方法可以帮助您:
但对于其他情况,据我所知,您需要自己实施解析。您可以尝试使用地图和一些闭包来减少一些样板文件:
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
既是双精度又是整数。
Groovy 有一些功能可以让您使这个逻辑更时髦。
- 强大的switch语句,支持正则表达式和闭包。
isInteger
和isDouble
来自 Groovy JDK 的内置 CharSequence 方法。遗憾的是,没有严格的isBoolean
所以我们需要自己实施。- 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
.