2013-01-03 43 views
2

你將如何將一個字符串存儲/表示爲long?然後將它堵塞到一個8字節的數組中?Java如何長期存儲/表示一個字符串。然後從長到字符串

事情我已經試過/與

String eidString = "Awesome!"; 
    ByteBuffer buf = ByteBuffer.allocate(8); 
    CharBuffer cbuf = buf.asCharBuffer(); 
    cbuf.put(eidString); 

    byte[] eid = ByteBuffer.allocate(8).putLong(cbuf ??); 

嘗試2

Long l = Long.valueOf("Awesome!"); 

    byte[] eid = ByteBuffer.allocate(8).putLong(l).array(); 

    long p = ByteBuffer.wrap(eid).getLong(); 

    System.out.println(p); 

工作學嘗試3

String input = "hello long world"; 

byte[] bytes = input.getBytes(); 
LongBuffer tmpBuf = ByteBuffer.wrap(bytes).asLongBuffer(); 

long[] lArr = new long[tmpBuf.remaining()]; 
for (int i = 0; i < lArr.length; i++) 
    lArr[i] = tmpBuf.get(); 

System.out.println(input); 
System.out.println(Arrays.toString(lArr)); 
// store longs... 

// ...load longs 
long[] longs = { 7522537965568945263L, 7955362964116237412L }; 
byte[] inputBytes = new byte[longs.length * 8]; 
ByteBuffer bbuf = ByteBuffer.wrap(inputBytes); 
for (long l : longs) 
    bbuf.putLong(l); 
System.out.println(new String(inputBytes)); 
+5

嗯,你知道的最大字符串長度,你可以用做這將是8個字符,對不對?你的兩個例子違反了這一點。 – mikeslattery

+0

你是否想要在一長串中存儲任意長度的字符串?換句話說,你想要使用的字符串的最大長度是多少? – russoue

+0

那麼java的utc轉換是如何工作的呢? – stackoverflow

回答

2

您需要將您的字符串編碼爲數字並將其反轉。

  • 您必須確定您需要的符號數量。例如64個符號需要6位。 32個符號需要5位。
  • 這將決定一個字符串的最大長度。例如對於6位=> 64/6 = 10個符號,對於8位=> 64/8 = 8個符號。例如除非您認爲並非所有的a-z都可用,否則「hello long world」將不適合。

完成此操作後,您可以按照解析10或36基數的相同方式對符號進行編碼。要返回到一個字符串,你可以做相反的事情(如打印一個10或36的數字)

可能的字符/符號的範圍是什麼? (您需要包含一個終止符號,因爲字符串的長度可能有所不同)

+0

太棒了,謝謝你的回覆。 – stackoverflow

1

爲了解析字符串轉換爲長,可以使用龍包裝類。

String myString = "1500000"; 
Long myLong = Long.parseLong(myString); 

塞住它爲8字節數組...

long value = myLong.longValue(); 
byte[] bytes = new byte[8]; 
for (int i = 0; i < bytes.length; i++) { 
    long mask = 0xFF00000000000000 >> (i * 8); 
    bytes[i] = (byte) (value & mask); 
} 

這個例子是大端。

如果你編碼一個字符串轉換爲長,那麼你可以這樣做:

String myString = "HELLO"; 
long toLong = 0; 
for (int i = 0; i < myString.length(); i++) { 
    long c = (long) myString.charAt(i); 
    int shift = (myString.length() - 1 - i) * 8; 
    toLong += c << shift; 
} 

這並沒有經過測試。它可能有一些錯誤。

+0

但是我需要將諸如「Hello」這樣的字符存儲在長整型中。你不能用包裝類來做到這一點。 Long.parseLong(「你好」)不會工作 – stackoverflow

+2

@stackoverflow:**爲什麼**你「需要」這樣做?這就像是說:「我需要將我的車停放在揹包裏,但拉鍊不會那麼遠!」當然,它不會 - 你爲什麼期望你的汽車能放在你的揹包裏? –

+0

@DanielPryden我問這個問題,看看解決方案。我在一個長的UDP數據包中攜帶了字母數字ID。我只是解碼器而不是編碼器。 – stackoverflow

0

您不需要那樣做。字符串有一個名爲getBytes()的方法。它直接爲你做轉換。與參數調用下面的方法「哈利路亞」

public static void strToLong(String s) throws IOException 
{ 
    byte[] bArr = s.getBytes(); 
    for(byte b : bArr) 
    { 
     System.out.print(" " + b); 
    } 
    System.out.println(); 

    System.out.write(bArr); 
} 

結果是

72 97 108 108 101 108 117 106 97 104 
Hallelujah 
2

如果接受有限的字符集:

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小號

+0

這很好,但如果我只需要字符A-Z呢?我試圖將所需位數減少到5,因此將字符串的最大長度減少到12,但我無法弄清楚如何在這裏推廣這些算法。 – Makario

+0

@Makario我會在今天晚些時候對你進行調查 –

+2

@Makario我已經用32位編碼選項更新了我的答案。比較兩種算法,瞭解它們在一般情況下的工作方式。 –

相關問題