string_more extends String and str with two utility traits:
StringExtfor in-place editing onStringStrExtfor the corresponding immutable operations on string slices
The crate focuses on small, allocation-aware helpers for padding, editing, boundary handling, and simple text analysis.
cargo add string_moreor add it manually:
[dependencies]
string_more = "0.4"See CHANGELOG.md for release notes and breaking changes.
use std::collections::BTreeMap;use string_more::{StrExt,StringExt};let centered = "rust".center('-',2);assert_eq!(centered,"--rust--");letmut value = String::from(" rust\t");
value.expand_tabs_in_place(2);
value.trim_in_place();assert_eq!(value,"rust");assert_eq!("🦀rust".truncate_to_chars(2),"🦀r");assert_eq!("foobar".common_prefix("foobaz"),"fooba");let frequencies = "Hello".byte_frequencies::<BTreeMap<_,_>>();assert_eq!(frequencies[&b'l'],2);StringExtmutatesStringin place.StrExtleaves the original value unchanged. Most transformation methods return a newString, while some analysis and slicing helpers return borrowed&strresults.- Most text operations are based on Unicode scalar values (
char), not grapheme clusters. - Methods that accept indices use byte offsets and require valid char boundaries.
- Most text-like inputs accepted by the API can be passed as
char,&str, orStringthrough the sealedEncodeUtf8trait.
char_frequencies counts Unicode scalar values, while byte_frequencies counts UTF-8 bytes:
use std::collections::BTreeMap;use string_more::StrExt;let s = "·x·";let char_frequencies = s.char_frequencies::<BTreeMap<_,_>>();assert_eq!(char_frequencies[&'·'],2);assert_eq!(char_frequencies[&'x'],1);let byte_frequencies = s.byte_frequencies::<BTreeMap<_,_>>();assert_eq!(byte_frequencies[&0xC2],2);assert_eq!(byte_frequencies[&0xB7],2);assert_eq!(byte_frequencies[&b'x'],1);trim_start_in_place,trim_end_in_place,trim_in_placefill_start_in_place,fill_end_in_place,center_in_placepad_start_to_in_place,pad_end_to_in_place,center_to_in_placeenclose_in_placeexpand_tabs_in_placestrip_prefix_in_place,strip_suffix_in_placetruncate_to_chars_in_placeshift_in_placereplace_in_place
use string_more::StringExt;letmut s = String::from(" foobar\t");
s.expand_tabs_in_place(2);
s.trim_in_place();
s.strip_prefix_in_place("foo");
s.enclose_in_place("[","]");assert_eq!(s,"[bar]");fill_start,fill_end,centerpad_start_to,pad_end_to,center_toencloseexpand_tabstruncate_to_charsshiftcommon_prefix,common_suffixlongest_common_substringlevenshtein_distance,hamming_distancechar_frequencies,byte_frequenciesnext_char_boundary,previous_char_boundaryjoin
use string_more::StrExt;assert_eq!("42".pad_start_to(5,'0'),"00042");assert_eq!("foobar".common_suffix("quxbar"),"bar");assert_eq!("sparrow".longest_common_substring("crow"),"row");assert_eq!(", ".join(["one","two","three"]),"one, two, three");use string_more::{StrExt,StringExt};assert_eq!("Hello".fill_start("-",3),"---Hello");assert_eq!("Hello".fill_end("-",3),"Hello---");assert_eq!("Hello".center("-",3),"---Hello---");assert_eq!("42".center_to(5,' ')," 42 ");letmut s = String::from("Hello");
s.enclose_in_place("[","]");assert_eq!(s,"[Hello]");use string_more::{StrExt,StringExt};assert_eq!("🦀rust".truncate_to_chars(2),"🦀r");assert_eq!("foobar".common_prefix("foobaz"),"fooba");assert_eq!("foobar".common_suffix("quxbar"),"bar");letmut s = String::from("foobar");
s.strip_prefix_in_place("foo");assert_eq!(s,"bar");use string_more::{StrExt,StringExt};assert_eq!("🦀".next_char_boundary(2),4);assert_eq!("🦀".previous_char_boundary(2),0);letmut s = String::from("HelloWorld!");
s.shift_in_place(5,1,' ');assert_eq!(s,"Hello World!");use string_more::StrExt;assert_eq!("kitten".levenshtein_distance("sitting"),3);assert_eq!("karolin".hamming_distance("kathrin"),Some(3));assert_eq!("abc🦀".longest_common_substring("zzabcx🦀y"),"abc");This crate contains a small amount of unsafe code in the in-place mutation layer.
The public API is covered by unit tests and doctests.
Contributions are welcome! Feel free to open an issue or submit a pull request.
This crate is licensed under the MIT License. See LICENSE for more details.