在给设备重命名时,设备对名字的存储空间一般都是多少字节,而并非多少字,并通常都是采用utf-8的编码。
那问题来了,utf-8的编码是1-6个字节的不等长度,如何获取将一个超过30字节的文本转换到30字节以内?
Java中获取utf-8文本的字节长度很简单,如下:
text.getBytes("utf-8").length
但是在把超过30个字节的字符串截取到30个字节的时候会导致乱码。
如字符串长度是31字节,字符串最后一个是汉字,汉字一般占用3个字节,也就是第[29,30,31]个字节才表示一个汉字,如果截取到30,那么最后的汉字只剩下[29,30]两位来表示了,这个时候就出现先了乱码。
现在就是如何解决取整移除一个字符,防止乱码的出现。
第一步,先把字符串转换为char数组,char在Java中占用两位字节,采用unicode编码;
第二步,把每个char的unicode转换为utf-8编码的长度,计算char的总长
| Unicode符号范围 | UTF-8编码方式
n | (十六进制) | (二进制)
---+-----------------------+------------------------------------------------------
1 | 0000 0000 - 0000 007F | 0xxxxxxx
2 | 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx
3 | 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
4 | 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5 | 0020 0000 - 03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 | 0400 0000 - 7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
根据如上Unicode符号与UTF-8编码的对应关系,可以编写一下程序来限制字节长度:
public static String getWholeText(String text, int byteCount){
try {
if (text != null && text.getBytes("utf-8").length > byteCount) {
char[] tempChars = text.toCharArray();
int sumByte = 0;
int charIndex = 0;
for (int i = 0, len = tempChars.length; i < len; i++) {
char itemChar = tempChars[i];
// 根据Unicode值,判断它占用的字节数
if (itemChar >= 0x0000 && itemChar <= 0x007F) {
sumByte += 1;
} else if (itemChar >= 0x0080 && itemChar <= 0x07FF) {
sumByte += 2;
} else {
sumByte += 3;
}
if (sumByte > byteCount) {
charIndex = i;
break;
}
}
return String.valueOf(tempChars, 0, charIndex);
}
} catch (UnsupportedEncodingException e) {
}
return text;
}
由于一个char只有两位,最多只能表示utf-8格式的3个字节,这里按照这种方式处理。
另外前面有说utf-8字节的长度是1-6位,这里只计算了3位以内表示的字符,依然不够严谨。下期将给出更为完善的计算方式,可以先参考来实现六位的表示。
附上限制Edittext输入的代码:
public class MaxLimitTextWatcher implements TextWatcher {
private int mMaxBytes;
private EditText mEditText;
public MaxLimitTextWatcher(EditText editText, int maxBytes) {
mEditText = editText;
mMaxBytes = maxBytes;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Editable editable = mEditText.getText();
int len = editable.toString().getBytes().length;
if(len > mMaxBytes)
{
int selEndIndex = Selection.getSelectionEnd(editable);
String str = editable.toString();
//截取新字符串
String newStr = getWholeText(str, mMaxBytes);
mEditText.setText(newStr);
editable = mEditText.getText();
//新字符串的长度
int newLen = editable.length();
//旧光标位置超过字符串长度
if(selEndIndex > newLen)
{
selEndIndex = editable.length();
}
//设置新光标所在的位置
Selection.setSelection(editable, selEndIndex);
}
}
@Override
public void afterTextChanged(Editable s) {
}
public static String getWholeText(String text, int byteCount){
try {
if (text != null && text.getBytes("utf-8").length > byteCount) {
char[] tempChars = text.toCharArray();
int sumByte = 0;
int charIndex = 0;
for (int i = 0, len = tempChars.length; i < len; i++) {
char itemChar = tempChars[i];
// 根据Unicode值,判断它占用的字节数
if (itemChar >= 0x0000 && itemChar <= 0x007F) {
sumByte += 1;
} else if (itemChar >= 0x0080 && itemChar <= 0x07FF) {
sumByte += 2;
} else {
sumByte += 3;
}
if (sumByte > byteCount) {
charIndex = i;
break;
}
}
return String.valueOf(tempChars, 0, charIndex);
}
} catch (UnsupportedEncodingException e) {
}
return text;
}
}