#string #slice #multi-byte #safe #indexing #byte-string #replace

safe-string

为 Rust 中的多字节字符串交互提供安全的接口,包括 IndexedStr, IndexedString 和 IndexedSlice

12 个版本

0.1.11 2024 年 6 月 21 日
0.1.10 2024 年 4 月 4 日

#340文本处理

Download history 213/week @ 2024-04-18 186/week @ 2024-04-25 146/week @ 2024-05-02 104/week @ 2024-05-09 131/week @ 2024-05-16 122/week @ 2024-05-23 164/week @ 2024-05-30 166/week @ 2024-06-06 190/week @ 2024-06-13 427/week @ 2024-06-20 182/week @ 2024-06-27 114/week @ 2024-07-04 108/week @ 2024-07-11 100/week @ 2024-07-18 147/week @ 2024-07-25 179/week @ 2024-08-01

每月下载 557
4 个 Crates 中使用 (通过 quoth)

MIT 许可证

22KB
391

safe-string

Crates.io docs.rs Build Status MIT License

此包提供对 String&str 的替换类型,允许通过字符进行安全索引,以避免恐慌和操作多字节 UTF-8 字符时常见的陷阱,即字符串的 字节长度 和同一字符串的 字符长度 不相同的情况。

具体来说,IndexedString (代替 String) 和 IndexedSlice (代替 &str) 允许进行 O(1) 切片和字符索引,并且在索引或切片时永远不会恐慌。

这是通过存储字符串中每个字符的字符偏移量以及原始 String 来实现的,并使用这些信息实时计算每个字符的字节偏移量。因此 IndexedString 的内存使用量约为正常 String 的两倍,但 IndexedSlice 和其他实现 IndexedStr 的类型在额外开销方面仅比常规 &str 切片/胖指针多一个 usize。理论上,这可以通过使用不安全的 Rust 减少到与胖指针相同的大小,但这样我们可以拥有完全安全的代码,并且差异可以忽略不计。

示例

use safe_string::{IndexedString, IndexedStr, IndexedSlice};

let message = IndexedString::from("Hello, 世界! 👋😊");
assert_eq!(message.as_str(), "Hello, 世界! 👋😊");
assert_eq!(message, "Hello, 世界! 👋😊"); // handy PartialEq impls

// Access characters by index
assert_eq!(message.char_at(7), Some(''));
assert_eq!(message.char_at(100), None); // Out of bounds access returns None

// Slice the IndexedString
let slice = message.slice(7..9);
assert_eq!(slice.as_str(), "世界");

// Convert slice back to IndexedString
let sliced_message = slice.to_indexed_string();
assert_eq!(sliced_message.as_str(), "世界");

// Nested slicing
let slice = message.slice(0..10);
let nested_slice = slice.slice(3..6);
assert_eq!(nested_slice.as_str(), "lo,");

// Display byte length and character length
assert_eq!(IndexedString::from_str("世界").byte_len(), 6); // "世界" is 6 bytes in UTF-8
assert_eq!(IndexedString::from_str("世界").len(), 2); // "世界" has 2 characters

// Demonstrate clamped slicing (no panic)
let clamped_slice = message.slice(20..30);
assert_eq!(clamped_slice.as_str(), "");

// Using `as_str` to interface with standard Rust string handling
let slice = message.slice(0..5);
let standard_str_slice = slice.as_str();
assert_eq!(standard_str_slice, "Hello");

无运行时依赖