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
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
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
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
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
if (i == 0) {
for (j = 0, k = 1
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
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
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
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)
}
}
}