从长字符串到四字符十六进制字符串的转换

Conversion from long to four-character hex string

更新问题 01/28/2016:

由于我的问题之前不是很清楚(我还在学习),这里重写我的post:

这是我发现自己的场景:

我编写了一些代码,用于从包含 GPS 坐标的日志文件中读取数据,这些坐标采用以下十六进制格式:

"X1 X2 X3 X4 Y1 Y2 Y3 Y4"

其中 X 是纬度分量,Y 是经度分量。我的代码通过本质上执行以下序列将这些消息转换为 latitude/longitude 的值(以度为单位):

String strHexLat = X1 + X2 + X3 + X4; //(X1X2X3X4 viewed as one hex value)
String strHexLon = Y1 + Y2 + Y3 + Y4; //(Y1Y2Y3Y4 viewed as one hex value)

int intLat = Integer.decode(strHexLat);
int intLon = Integer.decode(strHexLon);

if ((intLat & 0x40000000) != 0) {
    intLat |= 0x80000000;
}
if ((intLon  & 0x40000000) != 0) {
    intLon  |= 0x80000000;
}

double lat = (double) intLat / 3600000; // convert from MAS to DEG
double lon = (double) intLon / 3600000; // convert from MAS to DEG

尽管不是特别优雅,但上面的代码满足了我的要求。我真正的麻烦开始于逆转过程。我正在尝试编写一些代码,这些代码现在将以与现有文件相同的格式创建日志文件,从坐标开始并生成表示坐标的 8 字符十六进制数组。

以下片段是我目前执行此转换所必须的,以及样本输入、结果输出和所需输出:

(1) 将以度为单位的坐标转换为毫角秒:

/* TEST COORDINATES */
mLat = 42.281422;
mLon = -83.748552;

/* Convert values from degrees to milliarcseconds*/
long convLat = (long)(mLat * 3600000.0);
long convLon = (long)(mLon * 3600000.0);

输入:

mLat = 42.281422  
mLon = -83.748552  

输出:

convLat = 152213119  
convLon = -301494787  

期望输出:
上面的输出是根据需要的。

(2) 考虑负值:

/* Account for negative values */
if(convLat < 0) convLat = convLat & 0x00000000ffffffffL;
if(convLon < 0) convLon = convLon & 0x00000000ffffffffL;

输入:

convLat = 152213119  
convLon = -301494787  

输出:

convLat = 152213119  
convLon = 3993472509  

期望输出:
上面的输出是根据需要的。

(3) 将值拆分为 4 个值(现在只是尝试纬度分量):

/* Split into four values */
byte[] dataLat = new byte[4];
dataLat[0] = (byte) ( ( convLat >>> 24 ) & 0xff );
dataLat[1] = (byte) ( ( convLat >>> 16 ) & 0xff );
dataLat[2] = (byte) ( ( convLat >>> 8 ) & 0xff );
dataLat[3] = (byte) ( ( convLat >>> 0 ) & 0xff );

输入:

convLat = 152213119  

输出:

dataLat[0] = 9  
dataLat[1] = 18  
dataLat[2] = -106  
dataLat[3] = 127  

期望输出:
***** 我不完全确定负值。

(4) 将值转换为单个十六进制字符串:

/* Convert to 1 hex string per component */
String hexLat = Long.toHexString(convLat);
String hexLon = Long.toHexString(convLon);

输入:

convLat = 152213119  
convLon = 3993472509  

输出:

hexLat = "912967f"  
hexLon = "ee078dfd"  

期望输出:
这些值是有效的,可以转换回所需的度数值。

如果:
convLat = 152213119 被转换为“912967f”
我要:
convLat = 152213119 变成“09 12 96 7f”
其中:
四个十六进制值中的任何一个都可以是 1 位或 2 位数字,并且将在左侧填充 0,在这种情况下它只是第一个数字,但它可以是四个中的任何一个。

(5) 将值转换成4个十六进制字符串:

/* Convert to 4 hex strings per component */
String[] hexStringLat = new String[4];
hexStringLat[0] = Integer.toHexString(dataLat[0]);
hexStringLat[1] = Integer.toHexString(dataLat[1]);
hexStringLat[2] = Integer.toHexString(dataLat[2]);
hexStringLat[3] = Integer.toHexString(dataLat[3]);

输入:

dataLat[0] = 9  
dataLat[1] = 18  
dataLat[2] = -106  
dataLat[3] = 127  

输出:

hexStringLat[0] = "9"  
hexStringLat[1] = "12"  
hexStringLat[2] = "ffffff96"  
hexStringLat[3] = "7f"  

期望输出:
当转换为单个十六进制字符串时,我们得到值“912967f”

其中我想要的是上面提到的四个字符串的形式,“09 12 96 7f”。

然而,当直接转换为四个十六进制值时,我得到“9 12 ffffff96 7f”。
在这种情况下,填充操作很简单,但是我不希望 3 的值是负数。

问题:
为什么第三个值在直接转换为四个十六进制字符时为负,而在仅转换为一个十六进制字符串时却不是?

是否有 'easy' 方法将单个字符串转换为我想要的格式?
我可以写一些草率的代码到 运行 单个代码,通过它可以尝试不同的方法来拆分值,然后测试字符串是否转换回来,但这似乎是错误的方法。

注: 我发现以下内容有些帮助,但对于我所处的场景来说并不完整:
How to perform unsigned to signed conversion in Java?

在此先感谢您的帮助,如果我再次遗漏任何必要的细节,我深表歉意,如果您需要更多信息,请询问,我会尽快再次更新。

既然你已经有了经纬度的十六进制字符串,为什么不简单地拆分它,

Matcher m = Pattern.compile(".{1,2}").matcher(hexLat.toUpperCase());
String s1 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s2 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s3 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s4 = m.find() ? hexLat.substring(m.start(), m.end()) : "";

我还没有测试过这个,但是你不能使用String.format吗?

String.format ("%02X %02X %02X %02X", (byte) ( ( convLat >>> 24 ) & 0xff ),

也就是说,分解每个字节,就像您已经通过移位和屏蔽所做的那样,并将它们作为参数传递给 String.format。

02 确保两位数,必要时添加前导零。大写X表示使用十六进制,使用大写A-F。