有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

传感器可能不提供值的“数据类型描述”,因此: 我想通过分析接收到的字符串来了解数据类型

我在考虑使用正则表达式,但也许还有其他更好的方法。有什么建议吗


共 (3) 个答案

  1. # 1 楼答案

    我将创建一个数据验证器责任链,其每个元素将尝试将输入数据从限制性最强的类型转换为限制性最低的类型:

    boolean
    integer
    long
    float
    double
    String
    

    如果一个解析器未能解析数据,则链将其传播到下一个解析器,如果所有操作都失败,则抛出异常或将其用作字符串

  2. # 2 楼答案

    这篇文章激发了我的灵感,让我写出了自己的作品。它真的很容易使用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", " " }
    

    true/false的各种表示用于确定布尔性:

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

    可能的扩展可能包括为公式求值设置标志,或将返回的类型限制为“公共”类型(布尔、整数、双精度、字符串)的标志。此代码也可以在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};
    
      }
    
    }
    
  3. # 3 楼答案

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

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

    并捕捉每一步的异常 第二种方法-使用ApacheCommons库,可以检测类型,即

    BooleanUtils.isBoolean(s)    
    StringUtils.IsNumeric(s)
    StringUtils.IsAlpha(s)