首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有效地截断字符串复制‘`str`’到`[u8]‘(utf8感知的strlcpy)?

有效地截断字符串复制‘`str`’到`[u8]‘(utf8感知的strlcpy)?
EN

Stack Overflow用户
提问于 2017-02-06 08:19:56
回答 2查看 369关注 0票数 1

虽然Rust提供了str.as_bytes,但我希望将一个字符串复制到一个固定大小的缓冲区中,其中只有完整的unicode标量值被复制到缓冲区中,取而代之的是用一个在结尾处编写的空终止符截断,用C术语来说,我把它称为一个utf8 strlcpy (也就是说,它复制到一个固定大小的缓冲区中,并确保它的空终止)。

这是我想出的一个函数,但我希望在Rust中有更好的方法来做到这一点:

代码语言:javascript
复制
// return the number of bytes written to
pub fn strlcpy_utf8(utf8_dst: &mut [u8], str_src: &str) -> usize {
    let utf8_dst_len = utf8_dst.len();
    if utf8_dst_len == 0 {
        return 0;
    }
    let mut index: usize = 0;
    if utf8_dst_len > 1 {
        let mut utf8_buf: [u8; 4] = [0; 4];
        for c in str_src.chars() {
            let len_utf8 = c.len_utf8();
            let index_next = index + len_utf8;
            c.encode_utf8(&mut utf8_buf);
            if index_next >= utf8_dst_len {
                break;
            }
            utf8_dst[index..index_next].clone_from_slice(&utf8_buf[0..len_utf8]);
            index = index_next;
        }
    }
    utf8_dst[index] = 0;
    return index + 1;
}

注释):--我意识到这并不理想,因为多个UCS可能构成一个单一的字形,但是结果至少能够解码回一个str

EN

回答 2

Stack Overflow用户

发布于 2017-02-06 08:47:07

铁锈的str有一个方便的方法char_indices,当你需要知道实际的字符边界。这将立即在某种程度上简化您的功能:

代码语言:javascript
复制
pub fn strlcpy_utf8(utf8_dst: &mut [u8], str_src: &str) -> usize {
    let utf8_dst_len = utf8_dst.len();
    if utf8_dst_len == 0 {
        return 0;
    }
    let mut last_index = 0;
    for (idx, _) in str_src.char_indices() {
        if (idx+1) > utf8_dst_len {
            break;
        }
        last_index = idx;
    }
    utf8_dst[0..last_index].copy_from_slice(&str_src.as_bytes()[0..last_index]);
    utf8_dst[last_index] = 0;
    return last_index + 1;
}

游乐场

但是,实际上不需要迭代每个字符,除非是在复制时,因为在UTF8中很容易找到边界;Rust有str::is_char_boundary()。相反,这让您可以从结尾回顾:

代码语言:javascript
复制
pub fn strlcpy_utf8(utf8_dst: &mut [u8], str_src: &str) -> usize {
    let utf8_dst_len = utf8_dst.len();
    if utf8_dst_len == 0 {
        return 0;
    }
    let mut last_index = min(utf8_dst_len-1, str_src.len());
    while last_index > 0 && !str_src.is_char_boundary(last_index) {
        last_index -= 1;
    }
    utf8_dst[0..last_index].copy_from_slice(&str_src.as_bytes()[0..last_index]);
    utf8_dst[last_index] = 0;
    return last_index + 1;
}

游乐场

票数 4
EN

Stack Overflow用户

发布于 2017-02-06 10:23:42

基于克里斯·爱默生的回答和@Matthieu-m关于删除多余支票的建议。

代码语言:javascript
复制
// returns the number of bytes written to
pub fn strlcpy_utf8(utf8_dst: &mut [u8], str_src: &str) -> usize {
    let utf8_dst_len = utf8_dst.len();
    if utf8_dst_len == 0 {
        return 0;
    }
    // truncate if 'str_src' is too long
    let mut last_index = str_src.len();
    if last_index >= utf8_dst_len {
        last_index = utf8_dst_len - 1;
        // no need to check last_index > 0 here,
        // is_char_boundary covers that case
        while !str_src.is_char_boundary(last_index) {
            last_index -= 1;
        }
    }
    utf8_dst[0..last_index].clone_from_slice(&str_src.as_bytes()[0..last_index]);
    utf8_dst[last_index] = 0;
    return last_index + 1;
}

@ChrisEmerson:我发了这个帖子,因为这是我的项目使用的代码,如果你愿意的话,可以随时用修改来更新你的答案,我会删除这个答案。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42063162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档