尽可能短的唯一ID



我正在制作一个优化脚本的工具,现在我想将其中的所有名称压缩到最小。我为它启动了这个函数,但不知怎么的,它在长度超过2后就停止了。有更简单的方法吗?我只需要一个模式,生成一个字符串从a -> z开始,然后aa -> az ba -> bz等等。

    public String getToken() {
    String result = ""; int i = 0;
    while(i < length){
        result = result + charmap.substring(positions[i], positions[i]+1);
        positions[length]++;
        if (positions[current] >= charmap.length()){
            positions[current] = 0;
            if ( current < 1 ) {
                current++;length++;
            }else{
                int i2 = current-1;
                while( i2 > -1 ){
                    positions[i2]++;
                    if(positions[i2] < charmap.length()){
                        break;
                    }else if( i2 > 0 ){
                        positions[i2] = 0;
                    }else{
                        positions[i2] = 0;
                        length++;current++;
                    }
                    i2--;
                }

            }

        }
        i++;
    }
    return result;
}

不像其他问题!!我不只是想增加一个整数,长度增加太多了

我用过一个

public class AsciiID {
    private static final String alphabet= 
                   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private int currentId;
    public String nextId() {
        int id = currentId++;
        StringBuilder b = new StringBuilder();
        do {
            b.append(alphabet.charAt(id % alphabet.length()));
        } while((id /=alphabet.length()) != 0);
        return b.toString();
    }
}

我将使用基数为36或64(取决于大小写敏感性)的库,并使用整数运行它,在输出之前,将整数转换为基数为36/64的数字。您可以根据顺序来考虑,这更容易,并且输出值由可信库处理。

您可以使用:

Integer.toString(i++, Character.MAX_RADIX)

base36。它不会像Base64那样被大大压缩,但是你有一个一行的实现。

您可以搜索一些可以操作任意基数的数的库,例如27、37或更多。然后将该数字输出为字母数字字符串(类似于HEX,但使用a-zA-Z0-9)。

让我们假设我们只能输出ASCII(对于unicode这个问题得到…复杂):快速查看一下,它的可打印字符在[32126]范围内。因此,为了最有效地表示这个问题,我们必须对给定的94进制整数进行编码,并对生成的任何char加32。

你是怎么做到的?查看Sun在Integer.toString()中是如何做到的,并相应地进行调整。这可能比必要的要复杂,想想如何把一个数转换成以2为基数。最简单的形式就是一个循环,只有一个除法和模数

在您的工具中,您需要创建一个字典,它将包含每个唯一字符串和字符串本身的唯一整数id。当向字典中添加字符串时,为每个新添加的唯一字符串增加给定的id。一旦字典完成,您可以简单地将id转换为String,使用如下所示:

  static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  static final int CHARS_LENGTH = CHARS.length();
  public String convert(int id) {
    StringBuilder sb = new StringBuilder();
    do {
      sb.append(CHARS.charAt(id % CHARS_LENGTH));
      id = id / CHARS_LENGTH;
    } while(id != 0);
    return sb.toString();
  }    

此函数生成第n个双射数(第0个除外)。这是最理想的编码。(第0个将是空字符串。)

如果有10个可能的字符,0 - 9,按顺序生成:

  • 10个长度1的字符串,从"0"到"9"
  • 10*10个长度2的字符串,从"00"到"99"
  • 10*10*10个长度3的字符串,从"000"到"999"
  • 等。

示例使用了93个字符,因为我刚好需要这些字符用于Json。

private static final char[] ALLOWED_CHARS =
        " !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"
                .toCharArray();
private static final AtomicInteger uniqueIdCounter = new AtomicInteger();
public static String getToken() {
    int id = uniqueIdCounter.getAndIncrement();
    return toBijectiveNumber(id, ALLOWED_CHARS);
}
public static String toBijectiveNumber(int id, char[] allowedChars) {
    assert id >= 0;
    StringBuilder sb = new StringBuilder(8);
    int divisor = 1;
    int length  = 1;
    while (id >= divisor * allowedChars.length) {
        divisor *= allowedChars.length;
        length++;
        id -= divisor;
    }
    for (int i = 0; i < length; i++) {
        sb.append(allowedChars[(id / divisor) % allowedChars.length]);
        divisor /= allowedChars.length;
    }
    return sb.toString();
}

相关内容

  • 没有找到相关文章

最新更新