import javafx.util.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class FormatUtil {
private static final String ERROR = "error";
private static final char MASK = '*';
private static final char FILL = '.';
private static final Map<Character, Short> mapping = new HashMap<>();
private static final int STEP_0 = 0;
private static final int STEP_3 = 1;
private static final int STEP_15 = 2;
private static final int STEP_OVER_15 = 3;
private static final HeadBuilder hBuilder = new HeadBuilder();
private static final ContentBuilder cBuilder = new ContentBuilder();
public static void parseMapping(String s) {
try {
s = s.trim().replaceAll("\n", "");
String content = s.substring(1, s.length() - 1);
if (!s.startsWith("{") || !s.endsWith("}")) {
throw new Exception(" mapping {} format error");
}
String[] mappings = content.split(",");
String temp;
String[] t;
for (String s1 : mappings) {
s1 = s1.trim();
if (!s1.startsWith("[") || !s1.endsWith("]"))
throw new Exception(" mapping [] format error");
temp = s1.substring(1, s1.length() - 1);
t = temp.split(":");
mapping.put(t[0].charAt(0), Short.valueOf(t[1]));
}
} catch (Exception e) {
Log.e("Format", e.getMessage());
}
}
/**
* 压缩
*/
public static String on(String s) {
if (s == null || s.isEmpty())
return ERROR;
try {
char[] header = hBuilder.build(s);
short[] shorts = cBuilder.build(s);
StringBuilder stringBuilder = new StringBuilder();
for (char ch : header) {
stringBuilder.append(ch);
}
for (int x : shorts) {
stringBuilder.append((char) x);
}
return stringBuilder.toString();
} catch (Exception e) {
Log.e("format error :", s);
}
return ERROR;
}
/**
* 解压缩
*/
public static String off(String s) {
if (s == null || s.isEmpty())
return ERROR;
try {
char[] chars = hBuilder.unBuild(s);
StringBuilder stringBuilder = new StringBuilder(chars.length * 3);
for (char c : chars) {
stringBuilder.append(cBuilder.getOriginalChar((short) c));
}
//删除填充的小数点
cBuilder.trimPoint(stringBuilder);
cBuilder.trimPoint(stringBuilder);
for (int i : hBuilder.upCharIndex) {
stringBuilder.replace(i, i + 1, stringBuilder.substring(i, i + 1).toUpperCase());
}
return stringBuilder.toString();
} catch (Exception e) {
Log.e("Format off error:", e.getMessage());
}
return ERROR;
}
static final class HeadBuilder {
private final ArrayList<Integer> upCharIndex = new ArrayList<>(8);
public char[] build(String s) {
int len = s.length();
upCharIndex.clear();
int maxDistance = 0;
int lastIndex = 0, upCharCount = 0;
char c;
boolean b;
for (int i = 0; i < len; i++) {
c = s.charAt(i);
b = Character.isUpperCase(c);
if (b || c == FILL) {
if (i - lastIndex >= maxDistance) {
maxDistance = i - lastIndex;
}
upCharIndex.add(i - lastIndex);
lastIndex = i;
}
if (b) upCharCount++;
}
if (upCharCount == 0) {
char empty = FILL;
empty &= 0;
return new char[]{empty};
}
int type = stepType(maxDistance);
return handleHead(type);
}
public char[] unBuild(String s) {
char[] chars = s.toCharArray();
Pair<Integer, Integer> info = getInfoByHeadChar(chars[0]);
int size = getSizeByType(info.getValue()) + 1;
if (info.getKey() != 0) {
char[] c = new char[size];
System.arraycopy(chars, 0, c, 0, size);
unHandleHead(c, info.getKey(), size);
}
char[] c2 = new char[chars.length - size];
System.arraycopy(chars, size, c2, 0, chars.length - size);
return c2;
}
private void unHandleHead(char[] c, int stepType, int size) {
upCharIndex.clear();
int distance = getStepDistance(stepType);
if (distance != 0) {
int flag = getBitFlag(distance);
int d1 = 12 / distance;
int d2 = 16 / distance;
for (int i = 0; i < size; i++) {
if (i == 0) {
recoverCharIndex(c[i] << 4, d1, flag, distance);
} else {
recoverCharIndex(c[i], d2, flag, distance);
}
}
}
}
private void recoverCharIndex(int s, int d, int f, int distance) {
int k;
int index;
int lastIndex = upCharIndex.isEmpty() ? 0 : upCharIndex.get(upCharIndex.size() - 1);
for (k = 1; k <= d; k++) {
index = s & f;
if (distance == 3)
index >>= 13;
else if (distance == 4)
index >>= 12;
else if (distance == 6)
index >>= 10;
else {
continue;
}
if (upCharIndex.size() != 0 && index == 0)
return;
index = lastIndex + index;
upCharIndex.add(index);
lastIndex = index;
s = s << distance;
}
}
private int getBitFlag(int d) {
if (d == 3)
return 7 << 13;
if (d == 4)
return 15 << 12;
return 63 << 10;
}
/**
* 从首字符中取出,步长类型,填充字符个数类型
*
* @param h 首字符
* @return first:步长类型,second:填充字符个数类型
*/
public Pair<Integer, Integer> getInfoByHeadChar(char h) {
int stepType = h & 49152;//2^15+2^14;
int sizeType = h << 2 & 49152;
return new Pair<>(stepType >> 14, sizeType >> 14);
}
private char[] handleHead(int type) {
char ch = FILL;
ch &= 0;
ch = bitToLeft(ch, type, 14);
if (upCharIndex.size() == 0)
return new char[]{ch};
int stepDistance = getStepDistance(type);
int ch1 = 12 / stepDistance;
//每个字符可以存储几个位置
int sizeOfChar = 16 / stepDistance;
int size = upCharIndex.size() - ch1;
if (size < 0) {
size = 0;
ch1 = upCharIndex.size();
}
int n = (size % sizeOfChar == 0) ? 0 : 1;
size = size / sizeOfChar + n;
char[] chars = new char[size + 1];
ch = bitToLeft(ch, getTypeBySize(size), 12);
int k, j;
//记录大写字母位置与char中
for (int i = 0; i < chars.length; i++) {
if (i == 0) {
for (j = 0, k = 1; j < ch1; j++, k++) {
ch = bitToLeft(ch, upCharIndex.get(j), 12 - (k * stepDistance));
}
chars[i] = ch;
} else {
char emptyCh = FILL;
emptyCh &= 0;
int start = (i - 1) * sizeOfChar + ch1;
for (j = start, k = 1; j < start + sizeOfChar; j++, k++) {
if (j == upCharIndex.size())
break;
emptyCh = bitToLeft(emptyCh, upCharIndex.get(j), 16 - (k * stepDistance));
}
chars[i] = emptyCh;
}
}
return chars;
}
private char bitToLeft(char c, int i, int site) {
c |= i << site;
return c;
}
/**
* 获取步长。
*
* @param maxDistance 最长字符串
* @return 类型 STEP_0:长度为0,STEP_3:长度小于8的字符串,其他雷同。
*/
public int stepType(int maxDistance) {
if (maxDistance == 0)
return STEP_0;
if (maxDistance < 8) {
return STEP_3;
}
if (maxDistance > 15) {
return STEP_OVER_15;
}
return STEP_15;
}
/**
* 目前填充字符最大为3,如有更大,直接废弃。
*/
public int getTypeBySize(int size) {
return size;
}
public int getSizeByType(int t) {
return t;
}
private int getStepDistance(int type) {
if (type == 0)
return 0;
if (type == 1)
return 3;
return type == STEP_15 ? 4 : 6;
}
}
static final class ContentBuilder {
public short[] build(String s) {
s = handleString(s);
char[] chars = s.toCharArray();
short[] shorts = new short[chars.length / 3];
for (int i = 0, j = 0; i < chars.length; i += 3, j++) {
shorts[j] = buildShort(chars[i], chars[i + 1], chars[i + 2]);
}
return shorts;
}
public String handleString(String s) {
int f;
if ((f = s.length() % 3) != 0) {
StringBuilder sBuilder = new StringBuilder(s);
for (f = 3 - f; f > 0; f--)
sBuilder.append(FILL);
s = sBuilder.toString();
}
return s.toLowerCase();
}
public void trimPoint(StringBuilder stringBuilder) {
if (stringBuilder.lastIndexOf(String.valueOf(FILL)) == stringBuilder.length() - 1)
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
public String getOriginalChar(short s) {
int low = s & 31;
int mid = s >> 5 & 31;
int high = s >> 10 & 31;
Character[] characters = new Character[3];
int count = 0;
for (Map.Entry<Character, Short> entry : mapping.entrySet()) {
if (entry.getValue() == high) {
characters[0] = entry.getKey();
++count;
}
if (entry.getValue() == mid) {
characters[1] = entry.getKey();
++count;
}
if (entry.getValue() == low) {
characters[2] = entry.getKey();
++count;
}
if (count == 3)
break;
}
return String.valueOf(characters[0]) + characters[1] +
characters[2];
}
/**
* 将三个short合并成一个short
*
* @param high 合并到新Short的高位
* @param mid 合并到新mid的中间位
* @param low 合并到新Short的地位
* @return 新Short
*/
public short buildShort(char high, char mid, char low) {
short b = 0;
b |= getShortFromMapping(high) << 10;
b |= getShortFromMapping(mid) << 5;
b |= getShortFromMapping(low);
return b;
}
public short getShortFromMapping(char ch) {
if (mapping.containsKey(ch))
return mapping.get(ch);
return mapping.get(MASK);
}
}
}
Copy the code