Java如何从来自多个源的数据推断类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java如何从来自多个源的数据推断类型相关的知识,希望对你有一定的参考价值。

我正在开发一个从多个传感器收集数据的java服务器。这些传感器通常将查询的值作为字符串值返回。在标题中,它表示服务器必须使用的数据类型来转换接收的值。这些值可以是整数,布尔值,双精度,浮点数和长整数。

可能会发生传感器没有提供值的“数据类型描述”所以:我想找到一种方法来理解它分析接收到的字符串的数据类型。

我在考虑使用REGEX,但也许还有其他一些方法可以做得更好。有什么建议吗?

答案

有几种方法可以做到这一点。一种是尝试按正确的顺序解析不同的标准java类型的值,即

Boolean.parseBoolean(s)
Integer.parseInteger(s)
Long.parseLong(s)
... 
(and so on)

并且每一步捕获异常第二种方法 - 使用apache commons库,有类型的检测,即

BooleanUtils.isBoolean(s)    
StringUtils.IsNumeric(s)
StringUtils.IsAlpha(s)
另一答案

我将创建一个数据验证器责任链,其中每个元素都会尝试转换从最大限制类型到最少限制类型的输入数据:

boolean
integer
long
float
double
String

如果一个人无法解析数据,则链将其传播到下一个解析器,如果一切都失败,则抛出异常或将其用作String。

另一答案

我受这篇文章的启发来写我自己的文章。它真的很容易使用。 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" }

Byte,Short和Float的范围用于将可用的最窄类型的值包装起来:

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" }

默认类型是String,但如果方程式为parsable by the JavaScript ScriptEngine,则将解析if并返回结果

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" }

可能的扩展可能包括为公式评估设置一个标志,或者将返回类型限制为“common”类型(Boolean,Integer,Double,String)的标志。此代码也可以在gist.github找到。无论如何,这里是:

code

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};

  }

}

以上是关于Java如何从来自多个源的数据推断类型的主要内容,如果未能解决你的问题,请参考以下文章

在片段中创建自定义列表视图时出错。必需的活动,找到的片段

在 TypeScript 中,如何在具有多个类型参数的方法中推断出泛型类型参数?

如何通过一系列 lambdas 传递数据,其中参数类型是根据前一个 lambda 的返回类型推断的?

接口继承自System.Object吗?

VSCode创建自定义用户片段

linux打开终端如何启动scala,如何在终端下运行Scala代码片段?