gpt4 book ai didi

java - 如何在保持自然顺序的同时将 Java long 转换为字符串

转载 作者:搜寻专家 更新时间:2023-11-01 01:09:27 25 4
gpt4 key购买 nike

我目前正在研究一个简单的编程问题,优化它可能很有趣 - 至少对于那些相信编程是一门艺术的人来说是这样 :) 所以就是这样:

如何在保持自然顺序的同时最好地将 long 表示为字符串?

此外,字符串表示应匹配 ^[A-Za-z0-9]+$。 (我在这里并不太严格,但避免使用控制字符或任何可能导致编码问题的字符,在 XML 中是非法的,有换行符,或类似的字符肯定会导致问题)

这是一个 JUnit 测试用例:

@Test
public void longConversion() {
final long[] longs = { Long.MIN_VALUE, Long.MAX_VALUE, -5664572164553633853L,
-8089688774612278460L, 7275969614015446693L, 6698053890185294393L,
734107703014507538L, -350843201400906614L, -4760869192643699168L,
-2113787362183747885L, -5933876587372268970L, -7214749093842310327L, };

// keep it reproducible
//Collections.shuffle(Arrays.asList(longs));

final String[] strings = new String[longs.length];
for (int i = 0; i < longs.length; i++) {
strings[i] = Converter.convertLong(longs[i]);
}

// Note: Comparator is not an option
Arrays.sort(longs);
Arrays.sort(strings);

final Pattern allowed = Pattern.compile("^[A-Za-z0-9]+$");
for (int i = 0; i < longs.length; i++) {
assertTrue("string: " + strings[i], allowed.matcher(strings[i]).matches());
assertEquals("string: " + strings[i], longs[i], Converter.parseLong(strings[i]));
}
}

这是我正在寻找的方法

public static class Converter {
public static String convertLong(final long value) {
// TODO
}

public static long parseLong(final String value) {
// TODO
}
}

我已经对如何解决这个问题有了一些想法。尽管如此,我还是会从社区中得到一些不错的(创意)建议。

此外,如果这个转换是

  • 尽可能短
  • 易于用其他语言实现

编辑:我很高兴看到两个非常有名望的程序员遇到了和我一样的问题:对负数使用“-”是行不通的,因为“-”不会颠倒排序顺序:

  1. -0001
  2. -0002
  3. 0000
  4. 0001
  5. 0002

最佳答案

好的,拿两个:

class Converter {
public static String convertLong(final long value) {
return String.format("%016x", value - Long.MIN_VALUE);
}

public static long parseLong(final String value) {
String first = value.substring(0, 8);
String second = value.substring(8);
long temp = (Long.parseLong(first, 16) << 32) | Long.parseLong(second, 16);
return temp + Long.MIN_VALUE;
}
}

这个需要一点解释。首先,让我证明它是可逆的,并且由此产生的转换应该证明顺序:

for (long aLong : longs) {
String out = Converter.convertLong(aLong);
System.out.printf("%20d %16s %20d\n", aLong, out, Converter.parseLong(out));
}

输出:

-9223372036854775808 0000000000000000 -9223372036854775808
9223372036854775807 ffffffffffffffff 9223372036854775807
-5664572164553633853 316365a0e7370fc3 -5664572164553633853
-8089688774612278460 0fbba6eba5c52344 -8089688774612278460
7275969614015446693 e4f96fd06fed3ea5 7275969614015446693
6698053890185294393 dcf444867aeaf239 6698053890185294393
734107703014507538 8a301311010ec412 734107703014507538
-350843201400906614 7b218df798a35c8a -350843201400906614
-4760869192643699168 3dedfeb1865f1e20 -4760869192643699168
-2113787362183747885 62aa5197ea53e6d3 -2113787362183747885
-5933876587372268970 2da6a2aeccab3256 -5933876587372268970
-7214749093842310327 1be00fecadf52b49 -7214749093842310327

如您所见,Long.MIN_VALUELong.MAX_VALUE(前两行)是正确的,其他值基本一致。

这是在做什么?

假设您有带符号的字节值:

  • -128 => 0x80
  • -1 => 0xFF
  • 0 => 0x00
  • 1 => 0x01
  • 127 => 0x7F

现在,如果您将 0x80 添加到这些值中,您将获得:

  • -128 => 0x00
  • -1 => 0x7F
  • 0 => 0x80
  • 1 => 0x81
  • 127 => 0xFF

这是正确的顺序(有溢出)。

基本上,上面的操作是使用 64 位有符号长整数而不是 8 位有符号字节。

转换回来有点迂回。你可能认为你可以使用:

return Long.parseLong(value, 16);

但你不能。将 16 f 传递给该函数 (-1),它将抛出异常。它似乎将其视为一个无符号的十六进制值,long 无法容纳。因此,我将它分成两半并解析每一部分,将它们组合在一起,将前半部分左移 32 位。

关于java - 如何在保持自然顺序的同时将 Java long 转换为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2236385/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com