12 个版本
0.1.11 | 2024 年 6 月 21 日 |
---|---|
0.1.10 | 2024 年 4 月 4 日 |
#340 在 文本处理 中
每月下载 557 次
在 4 个 Crates 中使用 (通过 quoth)
22KB
391 行
safe-string
此包提供对 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");