Zookeeper-Binary OutputArchive의utf-8의 실현
이 코드 중 하나가 나의 주의를 끌었다.
/**
* create our own char encoder to utf8. This is faster
* then string.getbytes(UTF8).
* @param s the string to encode into utf8
* @return utf8 byte sequence.
*/
final private ByteBuffer stringToByteBuffer(CharSequence s) {
bb.clear();
final int len = s.length();
for (int i = 0; i < len; i++) {
if (bb.remaining() < 3) {
ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1);
bb.flip();
n.put(bb);
bb = n;
}
char c = s.charAt(i);
//
if (c < 0x80) {
bb.put((byte) c);
}
else if (c < 0x800) {
bb.put((byte) (0xc0 | (c >> 6)));
bb.put((byte) (0x80 | (c & 0x3f)));
} else {
bb.put((byte) (0xe0 | (c >> 12)));
bb.put((byte) (0x80 | ((c >> 6) & 0x3f)));
bb.put((byte) (0x80 | (c & 0x3f)));
}
}
bb.flip();
return bb;
}
코드의 주석에 의하면 이곳의 실현은 자바 자체보다 효율적이라고 한다.그렇다면 과연 어떨까?비교해서 한 번 배울 만하다.
우선 비교하기 전에 그들이 무엇을 하고 있는지 제거해야 한다.이 방식은 하나의 문자열이utf-8 인코딩 형식의 바이트 그룹으로 바뀌는 것을 실현했다.그러면utf-8 인코딩 형식은 어떻게 변환해야 합니까?일반적인 규칙은 다음과 같습니다.
1.단자 바이트의 기호에 대해 바이트의 첫 번째 자리는 0이고, 다음 7자리는 이 기호의 유니버설 코드이다.따라서 영어 문자의 경우 UTF-8 코드와 ASCII 코드가 동일합니다.
2.n 바이트의 기호(n>1)에 대해 첫 번째 바이트의 앞 n자리는 모두 1이고 n+1자리는 0이며 뒤 바이트의 앞 두 자리는 일률적으로 10이다.나머지 언급되지 않은 이진 비트는 모두 이 기호의 유니버설 코드입니다.
예는 다음과 같습니다.
1 바이트 0000 0000-0000 007F | 0xxxx
2바이트 0000 0080-0000 07FF | 110xxxx 10xxxx
3바이트 0000 08000-0000 FFF | 1110xxx 10xxx 10xxxx
4바이트0001 0000-0010 FFF | 11110xxx 10xxx 10xxx 10xxx 10xxx 10xxx
위의 규칙에 따라 코드를 이해하면 좀 편리할 것이다.stringToByteBuffer 메서드의 논리는 다음과 같습니다.
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null) throw new NullPointerException();
return StringCoding.encode(charsetName, value, 0, value.length);
}
더 이상 할 말이 없습니다. StringCoding 방법을 사용했습니다.코드 추적을 계속하려면:
static byte[] encode(String charsetName, char[] ca, int off, int len)
throws UnsupportedEncodingException
{
StringEncoder se = deref(encoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((se == null) || !(csn.equals(se.requestedCharsetName())
|| csn.equals(se.charsetName()))) {
se = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
se = new StringEncoder(cs, csn);
} catch (IllegalCharsetNameException x) {}
if (se == null)
throw new UnsupportedEncodingException (csn);
set(encoder, se);
}
return se.encode(ca, off, len);
}
이 코드의 대략적인 의미는 전달된 문자 집합의 이름에 따라 문자 집합을 찾은 다음에 문자 집합에 따라 StringEncoder 형식의 대상을 만드는 것으로 추측된다.그리고 대상의 encode 방법을 호출합니다.코드 추적을 계속하려면:
byte[] encode(char[] ca, int off, int len) {
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
이 코드는 StringEncoder의 유형을 판단합니다.나는 테스트 용례byte[]x="a"를 쓴다.getbytes("utf-8"); 추적 코드가 여기까지 왔는데 Array Encoder가 논리적으로 갔어요.계속해서 추적하여 Array Encoder의 여러 가지 실현을 발견하다.그중에 UTF 가 하나 있어요.8종류.이 종류는nio 가방에 있습니다.이 코드는 역컴파일링을 통해서만 볼 수 있으며 원본 패키지를 찾을 수 없습니다.
/* */ public int encode(char[] paramArrayOfChar, int paramInt1, int paramInt2, byte[] paramArrayOfByte)
/* */ {
/* 627 */ int i = paramInt1 + paramInt2;
/* 628 */ int j = 0;
/* 629 */ int k = j + Math.min(paramInt2, paramArrayOfByte.length);
/* 632 */ while ((j < k) && (paramArrayOfChar[paramInt1] < '')) {
/* 633 */ paramArrayOfByte[(j++)] = ((byte)paramArrayOfChar[(paramInt1++)]);
/* */ }
/* 635 */ while (paramInt1 < i)
/* */ {
/* 636 */ char c = paramArrayOfChar[(paramInt1++)];
/* 637 */ if (c < '-')
/* */ {
/* 639 */ paramArrayOfByte[(j++)] = ((byte)c);
/* */ }
/* 640 */ else if (c < 'ࠀ')
/* */ {
/* 642 */ paramArrayOfByte[(j++)] = ((byte)(0xC0 | c >> '\006'));
/* 643 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F));
/* */ }
/* 644 */ else if (Character.isSurrogate(c))
/* */ {
/* 645 */ if (this.sgp == null) {
/* 646 */ this.sgp = new Surrogate.Parser();
/* */ }
/* 647 */ int m = this.sgp.parse(c, paramArrayOfChar, paramInt1 - 1, i);
/* 648 */ if (m < 0)
/* */ {
/* 649 */ if (malformedInputAction() != CodingErrorAction.REPLACE) {
/* 650 */ return -1;
/* */ }
/* 651 */ paramArrayOfByte[(j++)] = replacement()[0];
/* */ }
/* */ else
/* */ {
/* 653 */ paramArrayOfByte[(j++)] = ((byte)(0xF0 | m >> 18));
/* 654 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 12 & 0x3F));
/* 655 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 6 & 0x3F));
/* 656 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | m & 0x3F));
/* 657 */ paramInt1++;
/* */ }
/* */ }
/* */ else
/* */ {
/* 661 */ paramArrayOfByte[(j++)] = ((byte)(0xE0 | c >> '\f'));
/* 662 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c >> '\006' & 0x3F));
/* 663 */ paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F));
/* */ }
/* */ }
/* 666 */ return j;
/* */ }
zookeeper와 차이가 많지 않고 비트 연산으로utf-8의 규칙을 실현한다.
비교 코드에 대한 이해는 다음과 같습니다.
여기까지utf-8의 실현은 끝났지만 여기는 나의 생각을 불러일으켰다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.