【问题标题】:How to get byte by byte from byte array如何从字节数组中逐字节获取
【发布时间】:2014-09-12 08:43:57
【问题描述】:

我收到来自服务器的响应,格式为

V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D410240x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101

然后我将它转换为字节数组,因为我需要从这个字节中获取值。

我尝试使用

Arrays.copyOfRange(original,
                        from , to);

但它是基于索引而不是基于字节的。

我也尝试了以下解决方案,但它也会根据长度截断字符串(如果我使用字符串而不是字节 [])。

public static String truncateWhenUTF8(String s, int maxBytes) {
    int b = 0;
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);

        // ranges from http://en.wikipedia.org/wiki/UTF-8
        int skip = 0;
        int more;
        if (c <= 0x007f) {
            more = 1;
        } else if (c <= 0x07FF) {
            more = 2;
        } else if (c <= 0xd7ff) {
            more = 3;
        } else if (c <= 0xDFFF) {
            // surrogate area, consume next char as well
            more = 4;
            skip = 1;
        } else {
            more = 3;
        }

        if (b + more > maxBytes) {
            return s.substring(0, i);
        }
        b += more;
        i += skip;
    }
    return s;
}

我知道如何计算字节长度的字符串,但它只给出字节的完整字符串长度,如

这是我需要按字节提取数据包的方法。

以上代码和参数仅为示例。我需要从字符串/字节数组中逐字节获取。

我搜索了很多,但没有得到任何我可以参考的解决方案或链接。我不知道如何使用字节长度拆分字符串,因为我知道每个参数和值的字节长度。

请给我任何参考或提示。

【问题讨论】:

  • 使用子字符串,因为格式/长度是已知的。如果您确实使用正则表达式,请考虑 match 而不是拆分。所以,无论如何.. 有什么问题是?此外,由于响应是一个字符串,因此最好考虑字符而不是字节。
  • 如果您非常了解字节和字节的概念,那么您可以根据您的要求划分字符串。
  • 实际上我们只需要使用字节来分割字符串,因为我只有这个参数的字节长度......
  • 我想要什么,从这个字符串中分割出一个字节
  • 仅供学习:你能告诉我为什么你的标题是9字节吗? V1YYZZ 6 字节 0x000001 1 字节 0x0D1 字节 0x0011 1 字节 20 ???我不知道如何处理20

标签: android string split byte


【解决方案1】:

要确定字符串中的一个字节等于多少并不是一件容易的事。您的字符串包含十六进制文本形式的字节:0x0D(一个字节,等于 13),但还包含作为子字符串的值。例如1024 可以解释为一个整数,在这种情况下适合 2 个字节,但也可以解释为由 4 个字符组成的文本,总计 8 个字节。

无论如何,我会使用正则表达式拆分字符串,然后将部分进一步拆分为长度和值:

String message = "V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D41024"+
    "0x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101";
String regex = "(0)(x)(\\w\\w)";
String[] parts = message.split(regex);
Log.d(TAG,"HEADER = "+parts[0]);
for (int i=1; i<parts.length; i++) {
    String s = parts[i];
    // Only process if it has length > 0
    if (s.length()>0) {
        String len = "", val = "";
        // String s is now in format LVVVV where L is the length, V is the value
        if (s.length() < 11) {
            // 1 character indicates length, up to 9 contains value
            len = s.substring(0, 1);
            val = s.substring(1);
        } else if (s.length() > 10) {
            // 2 characters indicate length, up to 99 contains value
            len = s.substring(0, 2);
            val = s.substring(2);
        } else if (s.length() > 101) {
            // 3 characters indicate length, up to 999 contains value
            len = s.substring(0, 3);
            val = s.substring(3);
        }
        Log.d(TAG, "Length: " + len + " Value: " + val);
    }
}

这会产生以下输出:

D/Activity: HEADER = V1YYZZ
D/Activity: Length: 0 Value: 001
D/Activity: Length: 1 Value: 1205
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 21 Value: TATADOCOMOINTERNET101

然后您可以检查包(不需要标题中的前两个包),将字符串转换为您想要的任何内容(例如Integer.parseInt(val))

如果您解释标头的结构 (V1YYZZ0x0000010x0D0x0011205),我可以改进我的答案以查找消息数。

【讨论】:

  • @SandipArmalPatil 你能解释一下标题吗?您的问题有什么进展吗?
  • “varam 代码”(可能应该是“参数代码”)(0x 分隔数据包的第一部分)似乎表明了参数值的用途和编码。如果您的测试输出包含它,那将会有所帮助。
【解决方案2】:

我认为扫描仪是可行的

import java.util.Scanner;

public class Library {

public static void main(String[] args) {
  String s = "V1YYZZ0x0000010x0D0x001120"
      + "50x0C152031962061900x0D410240x0E152031962061900x0F410240x1"
      + "021TATADOCOMOINTERNET101";

  // Skip first 9? bytes. I'm not sure how you define them
  // so I just assumed it is 26 chars long.
  s = s.substring(26, s.length());
  System.out.println(s);
  Scanner scanner = new Scanner(s);
  // Use byte as delimiter i.e. 0xDC, 0x00
  // Maybe you should use smth like 0x[\\da-fA-F]{2}
  // And if you want to know that byte, you should use
  // just 0x and get first 2 chars later
  scanner.useDelimiter("0x\\w{2}");
  // Easily extracted
  int numberOfParams = scanner.nextInt();
  for (int i = 0; i < numberOfParams; i++) {
      String extracted = scanner.next();
      // Length of message
      int l = extracted.length();
      boolean c = getLength(l) == getLength(l - getLength(l));
      l -= getLength(l);
      l = c ? l : l-1;

      System.out.println("length=" 
              + extracted.substring(0, extracted.length()-l));
      System.out.println("message=" 
              + extracted.substring(extracted.length()-l, extracted.length()));
  }
  // close the scanner
  scanner.close();
}
// Counting digits assuming number is decimal
private static int getLength(int l) {
    int length = (int) (Math.log10(l) + 1);
    System.out.println("counted length = " + length);
    return length;
}
}

我们肯定需要更多关于规则的信息,字符串是如何形成的。以及您需要做什么。这段代码可能对你来说已经足够好了。如果没有 cmets,它真的很短很简单。

【讨论】:

    【解决方案3】:

    这不是逐字节访问字节数组的答案,而是针对您发现自己的情况的答案。

    您的解释和描述看起来对您真正从服务器获得的内容感到困惑(例如,很难将“V1YYZZ0x0000010x0D0x001120”表示为 9 字节字段(注意它可能以 2 结尾) ,而不是 0))。或者,您使用错误的方法从服务器获取它,或者没有将其作为预期的数据类型获取。

    你的代码表明你相信你得到的是一个 UTF8 字符串。您问题中显示的数据似乎并未表明它打算采用该格式。

    请记住,在执行此类操作时,其他程序员必须为您看到的数据创建结构。他们必须在某个地方定义它,以使其能够被预期的接收者解码。除非有其他考虑(安全性、最小带宽等),否则这些格式通常以易于编码和解码的方式定义。

    存在多个“0x”-ASCII 编码的十六进制数字——尤其是表示参数的单个字节(在您的图形中称为“varam”)——强烈暗示该数据旨在被解释为 ASCII编码的字符串。虽然情况可能并非如此,但在从更大的角度看待问题时应牢记这一点。

    您必须花费太多精力来解码从服务器获取的信息。它可能应该相对容易,除非考虑到为什么会故意让它变得困难。

    所有这些都表明,真正的问题存在于您未向我们提供任何信息的领域。

    退后一步: 想想这样的事情: 你是如何从服务器接收到这个的(什么功能/接口)?
    在从服务器请求信息的调用中,有没有办法将编码类型指定为字节、ASCII 字符串或其他比 UTF8 更容易处理的格式?至少,数据显然不打算作为 UTF8 字符串处理。应该有一种方法可以让您在不将其转换为 UTF8 的情况下获取它。

    此外,您应该尝试找到数据格式的实际规范。您对来源的解释不多,因此可能是您正在对某些东西进行逆向工程并且无法访问规范。

    基本上,这似乎是一个好主意,最好退后一步,询问您是否从最容易解决的点开始,以及您是否朝着正确的方向前进。

    【讨论】:

    • 并且可能有一种方法可以要求服务器以更标准的格式(如 JSON、XML 等)进行响应。
    【解决方案4】:

    我确定我遗漏了一些明显的东西......

    String.getBytes();
    

    如果你想处理它以便从数组中获取定义的对象,只需使用包装

    ByteBuffer.wrap();
    

    结果大致如下:

    String s = "OUTPUT FROM SERVER";
    byte[] bytes = s.getBytes();
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    

    我在最初的问题中遗漏了什么? :/

    【讨论】:

      猜你喜欢
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多