我开发从多个传感器收集数据的Java服务器。 这些传感器通常返回查询值的字符串值。 在头它表明该服务器具有使用投接收到的值的数据类型。 这些值可以是整数,布尔值,双,float和长。
可能发生这样的传感器不提供值做的“数据类型描述”:我想找到一种方法来理解数据类型其分析接收到的字符串。
我在想使用正则表达式,但也许还有一些其他的方式做的更好。 任何建议?
我开发从多个传感器收集数据的Java服务器。 这些传感器通常返回查询值的字符串值。 在头它表明该服务器具有使用投接收到的值的数据类型。 这些值可以是整数,布尔值,双,float和长。
可能发生这样的传感器不提供值做的“数据类型描述”:我想找到一种方法来理解数据类型其分析接收到的字符串。
我在想使用正则表达式,但也许还有一些其他的方式做的更好。 任何建议?
有几种方法可以做到这一点。 一种是试图通过在正确的顺序,即不同的非标准的Java类型解析值
Boolean.parseBoolean(s)
Integer.parseInteger(s)
Long.parseLong(s)
...
(and so on)
和捕获异常每一步第二条本办法 - 使用Apache公共图书馆,有类型的检测,即
BooleanUtils.isBoolean(s)
StringUtils.IsNumeric(s)
StringUtils.IsAlpha(s)
我将创建责任的数据校验器链,其每个元素会试图从投最给限制最少的类型的顺序输入数据:
boolean
integer
long
float
double
String
如果一个失败,分析数据,环比它传播到下一个解析器,如果一切失败,则抛出一个异常,使用它作为字符串。
我被这个帖子的启发写我自己。 这是很容易使用。 串#TRIM()用来除去开头和结尾的空白,所以下面做工精细:
jshell> Typifier.typify(" 23 \t\n")
$206 ==> String[2] { "Byte", "23" }
jshell> Typifier.typify("\r\n 3.4")
$207 ==> String[2] { "Float", "3.4" }
但是,如果用户仅输入空格,这很好,太:
jshell> Typifier.typify(" ")
$298 ==> String[2] { "String", " " }
真正的各种表示/假用来确定布尔岬:
jshell> Typifier.typify(" F ")
$208 ==> String[2] { "Boolean", "false" }
jshell> Typifier.typify(" 1 ")
$209 ==> String[2] { "Boolean", "true" }
jshell> Typifier.typify(" TRUE ")
$210 ==> String[2] { "Boolean", "true" }
字节,短,浮动的范围用于盒中提供的最窄类型的值:
jshell> Typifier.typify(" 2 ")
$212 ==> String[2] { "Byte", "2" }
jshell> Typifier.typify(" 200 ")
$213 ==> String[2] { "Short", "200" }
jshell> Typifier.typify(" 2e9 ")
$214 ==> String[2] { "Float", "2.0E9" }
jshell> Typifier.typify(" 2e99 ")
$215 ==> String[2] { "Double", "2.0E99" }
默认类型为字符串,但如果方程是由JavaScript的ScriptEngine可分析的 ,如果将被解析,结果将返回
jshell> Typifier.typify("var a = 3; var b = 6; a*b")
$230 ==> String[2] { "Float", "18.0" }
jshell> Typifier.typify("2*(2.4e2 + 34.8)")
$231 ==> String[2] { "Float", "549.6" }
如果输入的字符串的长度为1,而不是布尔或字节,将被分配的字符类型:
jshell> Typifier.typify("4")
$232 ==> String[2] { "Byte", "4" }
jshell> Typifier.typify("-")
$233 ==> String[2] { "Character", "-" }
jshell> Typifier.typify("a")
$234 ==> String[2] { "Character", "a" }
可能的扩展可能包括将一个标志公式估计,或将限制返回类型标志为“普通”类型(布尔,整型,双精度,字符串)。 此代码也可以在发现gist.github 。 无论如何,在这里它是:
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Typifier {
public Typifier() {
// nothing special to do here
}
public static String[] typify (String data) {
String s = data.trim();
// -1. if the input data is only whitespace, return String
if (s.length() == 0) return new String[]{"String", data};
// 0. check if the data is Boolean (true or false)
if (Arrays.asList("0", "f", "F", "false", "False", "FALSE").contains(s))
return new String[]{"Boolean", "false"};
else if (Arrays.asList("1", "t", "T", "true", "True", "TRUE" ).contains(s))
return new String[]{"Boolean", "true"};
// 1. check if data is a Byte (1-byte integer with range [-(2e7) = -128, ((2e7)-1) = 127])
try {
Byte b = Byte.parseByte(s);
return new String[]{"Byte", b.toString()}; // if we make it to this line, the data parsed fine as a Byte
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not a Byte
}
// 2. check if data is a Short (2-byte integer with range [-(2e15) = -32768, ((2e15)-1) = 32767])
try {
Short h = Short.parseShort(s);
return new String[]{"Short", h.toString()}; // if we make it to this line, the data parsed fine as a Short
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not a Short
}
// 3. check if data is an Integer (4-byte integer with range [-(2e31), (2e31)-1])
try {
Integer i = Integer.parseInt(s);
return new String[]{"Integer", i.toString()}; // if we make it to this line, the data parsed fine as an Integer
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not an Integer
}
String s_L_trimmed = s;
// 4. check if data is a Long (8-byte integer with range [-(2e63), (2e63)-1])
// ...first, see if the last character of the string is "L" or "l"
if (Arrays.asList("L", "l").contains(s.substring(s.length() - 1)) && s.length() > 1)
s_L_trimmed = s.substring(0, s.length() - 1);
try {
Long l = Long.parseLong(s_L_trimmed);
return new String[]{"Long", l.toString()}; // if we make it to this line, the data parsed fine as a Long
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not a Long
}
// 5. check if data is a Float (32-bit IEEE 754 floating point with approximate extents +/- 3.4028235e38)
try {
Float f = Float.parseFloat(s);
if (!f.isInfinite()) // if it's beyond the range of Float, maybe it's not beyond the range of Double
return new String[]{"Float", f.toString()}; // if we make it to this line, the data parsed fine as a Float and is finite
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not a Float
}
// 6. check if data is a Double (64-bit IEEE 754 floating point with approximate extents +/- 1.797693134862315e308 )
try {
Double d = Double.parseDouble(s);
if (!d.isInfinite())
return new String[]{"Double", d.toString()}; // if we make it to this line, the data parsed fine as a Double
else // if it's beyond the range of Double, just return a String and let the user decide what to do
return new String[]{"String", s};
} catch (java.lang.NumberFormatException ex) {
// okay, guess it's not a Double
}
// 7. revert to String by default, with caveats...
// a. if string has length 1, it is a single character
if (s.length() == 1) return new String[]{"Character", s};
// b. if string contains any of {+, -, /, *, =}, attempt to parse equation
Pattern pattern = Pattern.compile("[+-/*=]");
Matcher matcher = pattern.matcher(s);
// ...evaluate the equation and send the result back to typify() to get the type
if (matcher.find()) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
String evaluated = engine.eval(s).toString();
return typify(evaluated);
} catch (javax.script.ScriptException ex) {
// okay, guess it's not an equation
}
}
// ...if we've made it all the way to here without returning, give up and return "String"
return new String[]{"String", s};
}
}