Skip to content

daddinuz/string_more

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

string_more

Crates.io Docs.rs License

string_more extends String and str with two utility traits:

  • StringExt for in-place editing on String
  • StrExt for the corresponding immutable operations on string slices

The crate focuses on small, allocation-aware helpers for padding, editing, boundary handling, and simple text analysis.

Installation

cargo add string_more

or add it manually:

[dependencies]
string_more = "0.4"

See CHANGELOG.md for release notes and breaking changes.

Quick Start

use std::collections::BTreeMap;
use string_more::{StrExt, StringExt};

let centered = "rust".center('-', 2);
assert_eq!(centered, "--rust--");

let mut 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);

API Notes

  • StringExt mutates String in place.
  • StrExt leaves the original value unchanged. Most transformation methods return a new String, while some analysis and slicing helpers return borrowed &str results.
  • 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, or String through the sealed EncodeUtf8 trait.

Frequency Example

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);

Overview

In-place editing with StringExt

  • trim_start_in_place, trim_end_in_place, trim_in_place
  • fill_start_in_place, fill_end_in_place, center_in_place
  • pad_start_to_in_place, pad_end_to_in_place, center_to_in_place
  • enclose_in_place
  • expand_tabs_in_place
  • strip_prefix_in_place, strip_suffix_in_place
  • truncate_to_chars_in_place
  • shift_in_place
  • replace_in_place
use string_more::StringExt;

let mut 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]");

Immutable helpers with StrExt

  • fill_start, fill_end, center
  • pad_start_to, pad_end_to, center_to
  • enclose
  • expand_tabs
  • truncate_to_chars
  • shift
  • common_prefix, common_suffix
  • longest_common_substring
  • levenshtein_distance, hamming_distance
  • char_frequencies, byte_frequencies
  • next_char_boundary, previous_char_boundary
  • join
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");

Selected Methods

Padding and enclosure

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  ");

let mut s = String::from("Hello");
s.enclose_in_place("[", "]");
assert_eq!(s, "[Hello]");

Truncation and prefix/suffix helpers

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");

let mut s = String::from("foobar");
s.strip_prefix_in_place("foo");
assert_eq!(s, "bar");

Boundary-aware indexing

use string_more::{StrExt, StringExt};

assert_eq!("🦀".next_char_boundary(2), 4);
assert_eq!("🦀".previous_char_boundary(2), 0);

let mut s = String::from("HelloWorld!");
s.shift_in_place(5, 1, ' ');
assert_eq!(s, "Hello World!");

Distances and substring search

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");

Safety and Coverage

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.

Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request.

License

This crate is licensed under the MIT License. See LICENSE for more details.

About

Extension traits for `String` and `&str`

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages