- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在寻找 Crockford Base32 的 Java 实现,它可以处理非常大的数字。这是我正在使用的数字类型的示例:
0003019140802085400304608040952
我见过几个使用 Long 编码和解码为 Long 的实现,但这比 Long 的最大值大得多。
我找到了这个实现,但它似乎给出了奇怪的结果: https://gist.githubusercontent.com/markov/5206312/raw/ba5ec8ff1ef894ac889d2d1fad359d51d91e8ab9/CrockfordBase32.java
上面的数字应该编码为 2E1BZQDAGC4G6TTENZR,但是这个实现并没有给我任何接近的东西。
最佳答案
这是 Base32 的一般实现,其中包含 Crockford 字符集的实现。它同时具有 format
和 parse
方法,这应该是免费的。
/**
* Parse and format base 32 numbers.
*
* Some of this may apply to almost any format but there's much that won't
* such as allowing both uppercase and lowercase forms of each digit.
*
* See: http://en.wikipedia.org/wiki/Base32
*/
public class Base32 {
// The character sets.
// Like Hex but up to V
private static final String base32HexCharacterSet = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
// Common alternative - avoids O/0, i/1 etc.
private static final String base32CharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
// Avoids vowels (and therefore real words)
private static final String zBase32CharacterSet = "YBNDRFG8EJKMCPQXOT1UWISZA345H769";
// Avoids o/0 confusion.
private static final String crockfordCharacterSet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
// Known/published formats.
// Uses the BigInteger formatter.
public static final Base32 ordinary = new Base32();
// A lot like the BigInteger formatter - but using my mechanism.
public static final Base32 base32Hex = new Base32(base32HexCharacterSet);
// The RFC 4648 Base32.
public static final Base32 base32 = new Base32(base32CharacterSet);
// Supposedly more natural than RFC 4648.
public static final Base32 zBase32 = new Base32(zBase32CharacterSet);
// Much like normal but recodes some similar looking characters to the same character.
public static final Base32 crockfords = new Base32(crockfordCharacterSet, "O0", "o0", "L1", "l1", "I1", "i1");
// Invalid character.
private static final int Invalid = -1;
// The radix - fixed at 32 bits.
private static final int radix = 32;
// The bits per digit - could use (int) (Math.log(radix) / Math.log(2))
private static final int bitsPerDigit = 5;
// The bits per byte.
private static final int bitsPerByte = 8;
// Translation table for each code.
private final char[] formatTable;
// Translation table for each character.
private final int[] parseTable;
// Constructor - Probably should be private but why restrict the user.
public Base32() {
// Empty tables makes us match BigInteger format so no formatting/parsing is required.
formatTable = null;
parseTable = null;
}
// Constructor with character set and optional extras :).
protected Base32(String characterSet, String... extras) {
// Check the character set against the radix.
if (characterSet.length() != radix) {
throw new NumberFormatException("Invalid character set. Must be " + radix + " long");
}
// Build the format table.
formatTable = buildFormatTable(characterSet);
// And the parse table.
parseTable = buildParseTable(characterSet, extras);
}
// Build a format table from the character set.
private char[] buildFormatTable(String characterSet) {
// Start clear.
char[] table = new char[radix];
// Put each character from the character set in.
for (int i = 0; i < radix; i++) {
table[i] = characterSet.charAt(i);
}
return table;
}
private int[] buildParseTable(String characterSet, String... extras) {
// Handle all characters up to and including 'z'.
int[] table = new int['z' + 1];
// By default invalid character.
Arrays.fill(table, Invalid);
// Lowercase and uppercase versions.
String lc = characterSet.toLowerCase();
String uc = characterSet.toUpperCase();
// Walk through the character set.
for (int i = 0; i < radix; i++) {
char l = lc.charAt(i);
char u = uc.charAt(i);
// Something wrong if we've already filled this one in.
if (table[l] == Invalid && table[u] == Invalid) {
// Put both lowercase and uppercase forms in the table.
table[l] = i;
table[u] = i;
} else {
// Failed.
throw new NumberFormatException("Invalid character set - duplicate found at position " + i);
}
}
// Add extras.
for (String pair : extras) {
// Each Must be length 2.
if (pair.length() == 2) {
// From
int f = pair.charAt(1);
// To
int t = pair.charAt(0);
// Something wrong if we've already filled this one in or we are copying from one that is not filled in.
if (table[f] != Invalid && table[t] == Invalid) {
// EG "O0" means a capital oh should be treated as a zero.
table[t] = table[f];
} else {
// Failed.
throw new NumberFormatException("Invalid character set extra - copying from " + f + " to " + t);
}
} else {
// Failed.
throw new NumberFormatException("Invalid extra \"" + pair + "\" - should be 2 characters wide.");
}
}
return table;
}
// Format a BigInteger.
public String format(BigInteger n) {
// Get its raw Radix32 string - in uppercase.
String formatted = n.toString(radix).toUpperCase();
// Further formatting through the format table?
if (formatTable != null) {
// Translate it.
char[] translated = new char[formatted.length()];
for (int i = 0; i < formatted.length(); i++) {
// Use Character.digit to decode the digit value.
int d = Character.digit(formatted.charAt(i), radix);
// Translate to that.
translated[i] = formatTable[d];
}
formatted = new String(translated);
}
return formatted;
}
// Parse a string.
public BigInteger parse(String s) {
BigInteger big;
// Pass it through the parse table if present.
if (parseTable != null) {
// Digits in the number.
int digits = s.length();
// Total bits (+1 to avoid sign bit).
int bits = digits * bitsPerDigit + 1;
// Number of bytes.
int bytes = (bits + bitsPerByte - 1) / bitsPerByte;
// Bias bits to slide to the right to get the bottom bit rightmost (+1 to avoid sign bit).
int bias = (bytes * bitsPerByte) - bits + 1;
// Make my array.
byte[] parsed = new byte[bytes];
// Walk the string.
for (int i = 0, bit = bias; i < digits; i++, bit += bitsPerDigit) {
// The character.
char c = s.charAt(i);
// Must be in the parse table.
if (c < parseTable.length) {
// Roll in each digit value into the correct bits.
int n = parseTable[c];
// Special cases.
switch (n) {
case 0:
// Nothing to do.
break;
default:
// How far to shift it to line up with "bit"
int shift = (bitsPerByte - bitsPerDigit - (bit % bitsPerByte));
// Sorry about the name.
int bite = bit / bitsPerByte;
// +ve shift is left into this byte.
if (shift >= 0) {
// Slide left only.
parsed[bite] |= n << shift;
} else {
// Split across this byte and the next.
parsed[bite] |= n >>> -shift;
// Slide right.
parsed[bite + 1] |= n << (bitsPerByte + shift);
}
break;
case Invalid:
// Must be mapped to something.
throw new NumberFormatException("Invalid character '" + c + "' at position " + i);
}
} else {
// Failed.
throw new NumberFormatException("Invalid character '" + c + "' at position " + i);
}
}
// Grow the biginteger out of the byte array.
big = new BigInteger(parsed);
} else {
// No parsing - it's ordinary.
big = new BigInteger(s, radix);
}
return big;
}
// Check a string.
public boolean good(String s) {
boolean good = true;
// Check each character.
for (int i = 0; i < s.length() && good; i++) {
// The character.
char c = s.charAt(i);
if (parseTable != null) {
if (c < parseTable.length) {
// Must be a valid character.
good = parseTable[c] != Invalid;
} else {
// Out of range of the parse table.
good = false;
}
} else {
// Use Character.digit - returns -1 if not valid.
good = Character.digit(c, radix) != -1;
}
}
return good;
}
public static void main(String args[]) {
Test.main(args);
}
}
class Test {
// For testing only.
private static Random r = new Random();
/*
* A 95 bit number fits in a 12 byte binary with a bit to spare (sign bit).
* A 95 bit number formats in base 32 to 19 digits exactly.
*
* Other numbers of this type:
* 15 bits 2 bytes 3 digits
* 55 bits 7 bytes 11 digits
* 95 bits 12 bytes 19 digits
* 135 bits 17 bytes 27 digits
* 175 bits 22 bytes 35 digits
* 215 bits 27 bytes 43 digits
* 255 bits 32 bytes 51 digits
*/
private static final int testBits = 95;
public static void main(String args[]) {
test(new BigInteger("10"));
test(new BigInteger("32"));
test(new BigInteger("100"));
BigInteger big = BigInteger.valueOf(0);
for (int i = 0; i < 1000; i++, big = big.add(BigInteger.ONE)) {
test(big);
}
for (int i = 0; i < 1000; i++) {
test(new BigInteger(testBits, r));
}
testCrockfords();
}
private static void test(BigInteger i) {
test(i, Base32.ordinary, "Ordinary");
test(i, Base32.base32Hex, "Base32Hex");
test(i, Base32.base32, "Base32");
test(i, Base32.crockfords, "Crockfords");
test(i, Base32.zBase32, "ZBase32");
}
private static void test(BigInteger i, Base32 f, String name) {
test(i, f, f.format(i), name);
}
private static void test(BigInteger i, Base32 f, String formatted, String name) {
BigInteger parsed = f.parse(formatted);
boolean ok = parsed.equals(i) && f.good(formatted);
//if (!ok) {
// For debug - so we can trace the issue.
BigInteger reParsed = f.parse(formatted);
boolean good = f.good(formatted);
System.out.println(i + " = " + f.format(i) + " in " + name + (ok ? " Ok" : " BAD!"));
if (!ok) {
System.out.println(reParsed + " != " + i);
}
//}
}
private static void testCrockfords() {
/// Crockford uses extras.
BigInteger anztenney = new BigInteger("0003019140802085400304608040952");
String formatted = Base32.crockfords.format(anztenney);
test(anztenney, Base32.crockfords, formatted, "Crockfords Test");
for (int i = 0; i < 100; i++) {
BigInteger b = BigInteger.valueOf(i);
formatted = Base32.crockfords.format(b);
test(b, Base32.crockfords, formatted, "Crockfords Test");
}
for (int i = 0; i < 1000; i++) {
BigInteger b = new BigInteger(testBits, r);
formatted = Base32.crockfords.format(b)
.replace('0', 'O')
.replace('1', 'l');
test(b, Base32.crockfords, formatted, "Crockfords Test");
}
}
}
注意:请彻底测试 - 这从未以严肃的方式使用过,因此可能存在错误。
测试确实输出了一行:
3019140802085400304608040952 = 2E1BZQDAGC4G6TTENZR in Crockfords Test Ok
所以您的电话号码似乎翻译正确。
关于java - 大数的Crockford base32编码——Java实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22385467/
我已经花了不少时间编写我的代码(它不起作用)。这是一个欧拉计划问题,其中给定一个非常大的和来查找,然后要求打印该和的前十位数字。 (问题可以在这里找到:https://projecteuler.net
我正在构建一个基于大整数的 C 库。基本上,我正在寻找一种快速算法来将二进制表示中的任何整数转换为十进制数 我看到了 JDK 的 Biginteger.toString() 实现,但对我来说它看起来很
C++ 编程新手。有没有办法使代码更好,使其没有重复代码。 if (totalDistance < pow(10, 3)) { cout << "\nTotal (approx) travel
我正在开发一个 3D 太空游戏,它使用了大量的数学公式、导航、缓动效果、旋转、行星之间的巨大距离、物体质量等等...... 我的问题是使用数学的最佳方法是什么。我应该将所有内容都计算为整数并获得非
我尝试用 JS 的取模函数计算,但没有得到正确的结果(应该是 1)。这是一段硬编码的代码。 var checkSum = 210501700012345678131468; alert(checkSu
美好的一天我正在尝试对 10000 个数字使用快速排序,但它给我堆栈溢出错误。它适用于随机数,但不适用于递减和递增的数字。 '谢谢 void quickSort(long* array, long s
在 Codewars 上找到这个。该函数接受两个参数 A 和 B,并返回 A^B 的最后一位。下面的代码通过了前两个测试用例,但不会通过下一个测试用例。 def last_digit(n1, n2):
复制代码 代码如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include
我需要一些帮助来决定什么更好 性能 明智的。 我正在与 一起工作bigints (超过 500 万位)并且大部分计算(如果不是全部)都在将当前 bigint 加倍。所以我想知道 是否更好乘每个单元格(
我正在对字符串执行一些 mod 算术类型的操作,其中每个字符都会获得特定的初始值(取决于其 ascii)和字符串中的位置。这些数字变得非常大,因为它们的初始值为 (ascii)*26^charPos。
这个问题在这里已经有了答案: Calculating pow(a,b) mod n (14 个答案) 关闭 6 年前。 在 Javascript 中是否有获取大数模数的技巧。我用 modulo(7,
我一直在努力为我的大学完成以下作业。到目前为止,我已经多次在这项作业上得到帮助(我真的很感激)。 由于这是大学作业,我希望能提供非直接的答案,这些答案可以通过不直接解决我的作业的示例来解释概念。 作业
我正在处理无法四舍五入的大量数字。使用 Lua 的标准数学库,似乎没有方便的方法来保持超出某些内部限制的精度。我还看到有几个库可以加载以处理大数字: http://oss.digirati.com.b
我有一个数据文件 (csv) Nilsimsa哈希值。其中一些可能长达 80 个字符。我希望在 Python 中阅读它们以完成数据分析任务。有没有办法在不丢失信息的情况下在python中导入数据? 编
我是一名优秀的程序员,十分优秀!