String#unpack对应的UTF-8是怎么回事?

[url=http://www.iteye.com/topic/201531]Ruby每周一测 - 中英文混合字符串截取[/url]

Quake Wang发的这个测试相当有趣,值得一看。我也算是被Ruby的字符编码问题困扰了好段时间了,这次果然又中招了。
老庄的解法:
[quote="庄表伟"]
def truncate_u(text, length = 30, truncate_string = "...")
l=0
char_array=text.unpack("U*")
char_array.each_with_index do |c,i|
l = l+ (c<127 ? 0.5 : 1)
if l>=length
return char_array[0..i].pack("U*")+(i<char_array.length-1 ? truncate_string : "")
end
end
return text
end
[/quote]

看到老庄的解法,我的第一直觉是:UTF-8中CJK应该是三字节的啊,这样unpack之后算出来的值不是不对了么?然后看看RDoc怎么说的:
[code]-------+---------+-----------------------------------------
U | Integer | UTF-8 characters as unsigned integers
-------+---------+-----------------------------------------[/code]
看到这个文档我还以为是把UTF-8的字符串拆成字节,结果原来是每个字符对应一个整型数字。

可是这个对应关系到底是怎样的……String#unpack的实现在pack.c里:
[code]case 'U':
if (len > send - s) len = send - s;
while (len > 0 && s < send) {
long alen = send - s;
unsigned long l;

l = utf8_to_uv(s, &alen);
s += alen; len--;
rb_ary_push(ary, ULONG2NUM(l));
}
break;[/code]

然后单个字符的转换函数是:
static unsigned long
utf8_to_uv(p, lenp)
char *p;
long *lenp;
{
int c = *p++ & 0xff;
unsigned long uv = c;
long n;

if (!(uv & 0x80)) {
*lenp = 1;
return uv;
}
if (!(uv & 0x40)) {
*lenp = 1;
rb_raise(rb_eArgError, "malformed UTF-8 character");
}

if (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
else {
*lenp = 1;
rb_raise(rb_eArgError, "malformed UTF-8 character");
}
if (n > *lenp) {
rb_raise(rb_eArgError, "malformed UTF-8 character (expected %d bytes, given %d bytes)",
n, *lenp);
}
*lenp = n--;
if (n != 0) {
while (n--) {
c = *p++ & 0xff;
if ((c & 0xc0) != 0x80) {
*lenp -= n + 1;
rb_raise(rb_eArgError, "malformed UTF-8 character");
}
else {
c &= 0x3f;
uv = uv << 6 | c;
}
}
}
n = *lenp - 1;
if (uv < utf8_limits[n]) {
rb_raiserb_eArgError, "redundant UTF-8 sequence");
}
return uv;
}

先确定UTF-8字符的长度(字节数),然后在while循环里编码……但是那几个magic number到底是什么意思我还是没弄明白,主要是那个0x3f和6。回去翻翻UTF-8的说明再看看……
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值