如果接受有限的字符集:
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
0,1,2,3,4,5,6,7,8,9, , <-- space character
,那麼你將在有63個符號的縮小字母表R
。每個符號可以映射到6位表示(64位組合的唯一位)。有一個隱含的第64個符號,它是用於標記字符串終止的空符號,應該用0x00
表示。這給我們留下了一個字母表R
映射到6比特作爲雙射。
A long
具有64位信息。由於64/6 = 10
,這意味着我們可以存儲一個字符串在Java long
變量最多10個字符的長度從字母表R
。
值得注意的是,即使R
是減少的字母表,我們有10個字符串長度的限制,我們仍然可以表達有意義的英語短語,他們轉換爲long
,然後再返回!
Java代碼的(64比特映射):
public static long stringToLong(String s) {
if(s.length() >10) { throw new IllegalArgumentException("String is too long: "+s); }
long out = 0L;
for(int i=0; i<s.length(); ++i) {
long m = reducedMapping(s.codePointAt(i));
if (m==-1) { throw new IllegalArgumentException("Unmapped Character in String: "+s); }
m <<= ((9-i)*6)+4;
out |= m;
}
return out;
}
public static String longToString(long l) {
String out = "";
long m = 0xFC00000000000000L;
for(int i=0; i<10; ++i,m>>>=6) {
int x =(int)((l&m) >>> (((9-i)*6)+4));
if(x==0) { break; }
out += mapping[x];
}
return out;
}
public static long reducedMapping(int x) {
long out=-1;
if(x >= 97 && x <= 122) { out = (long)(x-96); } // 'a' => 1 : 0x01
else if(x >= 65 && x <= 90) { out = (long)(x-37); } // 'A' => 27 : 0x1B
else if(x >= 48 && x <= 57) { out = (long)(x-+5); } // '0' => 53 : 0x35
else if(x == 32) { out = 63L; } // ' ' => 63 : 0x3F
return out;
}
public static char[] mapping = {
'\n', //<-- unused/empty character
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9',' '
};
Java代碼的(32比特映射):
public static long stringToLong32(String s) {
if(s.length() >12) { throw new IllegalArgumentException("String is too long: "+s); }
long out = 0L;
for(int i=0; i<s.length(); ++i) {
long m = reducedMapping32(s.codePointAt(i));
if (m==-1) { throw new IllegalArgumentException("Unmapped Character in String: "+s); }
m <<= ((11-i)*5)+4;
out |= m;
}
return out;
}
public static String longToString32(long l) {
String out = "";
long m = 0xF800000000000000L;
for(int i=0; i<12; ++i,m>>>=5) {
int x =(int)((l&m) >>> (((11-i)*5)+4));
if(x==0) { break; }
out += mapping32[x];
}
return out;
}
public static long reducedMapping32(int x) {
long out=-1;
if(x >= 97 && x <= 122) { out = (long)(x-96); } // 'a' => 1 : 0x01
else if(x >= 65 && x <= 90) { out = (long)(x-64); } // 'A' => 1 : 0x01
else if(x >= 32 && x <= 34) { out = (long)(x-5); } // ' ','!','"' => 27,28,29
else if(x == 44) { out = 30L; } // ',' => 30 : 0x1E
else if(x == 46) { out = 31L; } // '.' => 31 : 0x1F
return out;
}
public static char[] mapping32 = {
'\n', //<-- unused/empty character
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
' ','!','"',',','.'
};
}
編輯:
使用此類進行更一般化的轉換。它允許任何非空字符集中的Strings
唯一唯一地映射到long
並再次轉換回原始String
。只需通過構造函數定義任何字符集(char[]
),然後使用生成的對象來回轉換即可使用str2long
& long2str
。
的Java StringAndLongConverter
類:
import java.util.Arrays;
import java.util.regex.Pattern;
public class StringAndLongConveter {
/* .,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,., */
/* String <--> long ID Conversion */
/* `'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`' */
/* --<[ Class Members ]>-- */
// Don't re-arrange, order-dependent initializations
private final char[] CHAR_MAP;
public final int NUM_ACTUAL_CHARS;
public final int NUM_MAPPED_CHARS;
public final int BIT_COUNT;
public final int MAX_NUM_CHARS;
public final long ROLLING_MASK;
public final long FORMAT_MASK;
public final long MIN_VALUE;
public final long MAX_VALUE;
public final Pattern REGEX_CHAR_VALIDATOR;
public StringAndLongConveter(char[] chars) {
if(chars == null ) { throw new IllegalArgumentException("Cannot Pass in null reference"); }
if(chars.length==0) { throw new IllegalArgumentException("Cannot Pass in empty set" ); }
CHAR_MAP = setCharMap(chars);
NUM_ACTUAL_CHARS = CHAR_MAP.length;
NUM_MAPPED_CHARS = NUM_ACTUAL_CHARS+1;
BIT_COUNT = calcMinBitsNeeded();
MAX_NUM_CHARS = calcMaxPossibleChars();
ROLLING_MASK = calcRollingMask();
FORMAT_MASK = calcFormatMask();
MIN_VALUE = calcIDMinVal();
MAX_VALUE = calcIDMaxVal();
REGEX_CHAR_VALIDATOR = createRegExValidator();
}
/* --<[ Dynamic Initialization Calculation Helper Methods ]>-- */
//Remove duplicates
private final char[] setCharMap(final char[] chars) {
char[] tmp = new char[chars.length];
int dupes = 0;
for(int i=0; i<chars.length; ++i) {
boolean dupeFound = false;
for(int j=0; !dupeFound && j<i; ++j) {
if(chars[i]==chars[j]) {
++dupes;
dupeFound = true;
}
}
if(!dupeFound) { tmp[i-dupes] = chars[i]; }
}
char[] out = new char[chars.length-dupes];
if(dupes==0) { out = chars; }
else {
for(int i=0; i<out.length; ++i) out[i] = tmp[i];
}
return out;
}
// calculate minimum bits necessary to encode characters uniquely
private final int calcMinBitsNeeded() {
if(NUM_MAPPED_CHARS==0) { return 0; }
int val,tmp,log;
val = NUM_MAPPED_CHARS;
tmp = Integer.highestOneBit(val); // returns only the highest set bit
tmp = tmp | (tmp-1); // propagate left bits
log = Integer.bitCount(tmp); // count bits (logarithm base 2)
return ((val&(val-1))==0) ? log-1 : log;
//return one less then bit count if even power of two
}
//Calculate maximum number of characters that can be encoded in long
private final int calcMaxPossibleChars() {
return Long.SIZE/BIT_COUNT;
}
//Calculate rolling mask for str <--> long conversion loops
private final long calcRollingMask() {
long mask = 0x0000000000000001L;
for(int i=1; i<BIT_COUNT; ++i) { mask |= mask << 1; }
for(int i=1; i<MAX_NUM_CHARS; ++i) { mask <<= BIT_COUNT; }
return mask;
}
//Calculate format mask for long input format validation
private final long calcFormatMask() {
//propagate lest significant set bit in rolling mask & negate resulting value
return ~(ROLLING_MASK | (ROLLING_MASK-1));
}
//Calculate min value of long encoding
//doubles as format specification for unused bits
private final long calcIDMinVal() {
return 0xAAAAAAAAAAAAAAAAL & FORMAT_MASK;
}
//Calculate max value of long encoding
private final long calcIDMaxVal(){
char maxChar = CHAR_MAP[CHAR_MAP.length-1];
char[] maxCharArr = new char[MAX_NUM_CHARS];
Arrays.fill(maxCharArr, maxChar);
return str2long(new String(maxCharArr));
}
//Dynamically create RegEx validation string for invalid characters
private final Pattern createRegExValidator() {
return Pattern.compile("^["+Pattern.quote(new String(CHAR_MAP))+"]+?$");
}
/* --<[ Internal Helper Methods ]>-- */
private static boolean ulongLessThen(long lh, long rh) {
return (((lh^rh) >> 63) == 0) ? lh < rh : (0x8000000000000000L & lh)==0;
}
private long charMapping(final char c) {
for(int i=0; i<CHAR_MAP.length; ++i)
if(CHAR_MAP[i]==c)
return i+1;
return -1;
}
/* --<[ String <--> long Conversion Methods ]>-- */
public final String long2str(final long n) {
String out = "";
if (ulongLessThen(n,MIN_VALUE) || ulongLessThen(MAX_VALUE,n)) { throw new IllegalArgumentException("Long Outside of Formatted Range: "+Long.toHexString(n)); }
if ((FORMAT_MASK & n) != MIN_VALUE) { throw new IllegalArgumentException("Improperly Formatted long"); }
long m = ROLLING_MASK;
for(int i=0; i<MAX_NUM_CHARS; ++i,m>>>=BIT_COUNT) {
int x =(int)((n&m) >>> ((MAX_NUM_CHARS-i-1)*BIT_COUNT));//10|10 0111
if(x >= NUM_MAPPED_CHARS) { throw new IllegalArgumentException("Invalid Formatted bit mapping: \nlong="+Long.toHexString(n)+"\n masked="+Long.toHexString(n&m)+"\n i="+i+" x="+x); }
if(x==0) { break; }
out += CHAR_MAP[x-1];
}
return out;
}
public final long str2long(String str) {
if(str.length() > MAX_NUM_CHARS) { throw new IllegalArgumentException("String is too long: "+str); }
long out = MIN_VALUE;
for(int i=0; i<str.length(); ++i) {
long m = charMapping(str.charAt(i));
if (m==-1) { throw new IllegalArgumentException("Unmapped Character in String: "+str); }
m <<= ((MAX_NUM_CHARS-i-1)*BIT_COUNT);
out += m; // += is more destructive then |= allowing errors to be more readily detected
}
return out;
}
public final boolean isValidString(String str) {
return str != null && !str.equals("") //null or empty String
&& str.length() <= MAX_NUM_CHARS //too long
&& REGEX_CHAR_VALIDATOR.matcher(str).matches(); //only valid chars in string
}
public final char[] getMappedChars() { return Arrays.copyOf(CHAR_MAP,CHAR_MAP.length); }
}
玩得開心編碼&解碼String
小號& long
小號
嗯,你知道的最大字符串長度,你可以用做這將是8個字符,對不對?你的兩個例子違反了這一點。 – mikeslattery
你是否想要在一長串中存儲任意長度的字符串?換句話說,你想要使用的字符串的最大長度是多少? – russoue
那麼java的utc轉換是如何工作的呢? – stackoverflow