malachite_base/strings/mod.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::named::Named;
10use alloc::string::String;
11use alloc::vec::Vec;
12use core::fmt::{Binary, Debug, LowerHex, Octal, UpperHex};
13use hashbrown::HashSet;
14use itertools::Itertools;
15
16/// Sorts the characters of a string slice and returns them in a new [`String`].
17///
18/// # Worst-case complexity
19/// $T(n) = O(n \log n)$
20///
21/// $M(n) = O(n)$
22///
23/// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
24///
25/// # Examples
26/// ```
27/// use malachite_base::strings::string_sort;
28///
29/// assert_eq!(string_sort("Hello, world!"), " !,Hdellloorw");
30/// assert_eq!(string_sort("Mississippi"), "Miiiippssss");
31/// ```
32pub fn string_sort(s: &str) -> String {
33 let mut chars = s.chars().collect_vec();
34 chars.sort_unstable();
35 chars.iter().collect()
36}
37
38/// Takes a string slice's unique characters and returns them in a new [`String`].
39///
40/// The unique characters are output in order of appearance.
41///
42/// # Worst-case complexity
43/// $T(n) = O(n)$
44///
45/// $M(n) = O(n)$
46///
47/// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
48///
49/// # Examples
50/// ```
51/// use malachite_base::strings::string_unique;
52///
53/// assert_eq!(string_unique("Hello, world!"), "Helo, wrd!");
54/// assert_eq!(string_unique("Mississippi"), "Misp");
55/// ```
56pub fn string_unique(s: &str) -> String {
57 let mut chars = HashSet::new();
58 let mut nub = String::new();
59 for c in s.chars() {
60 if chars.insert(c) {
61 nub.push(c);
62 }
63 }
64 nub
65}
66
67/// Returns whether all of the first string slice's characters are present in the second string
68/// slice.
69///
70/// Does not take multiplicities into account.
71///
72/// # Worst-case complexity
73/// $T(n) = O(n)$
74///
75/// $M(n) = O(n + m)$
76///
77/// where $T$ is time, $M$ is additional memory, $n$ is `s.len()`, and $m$ is `t.len()`.
78///
79/// # Examples
80/// ```
81/// use malachite_base::strings::string_is_subset;
82///
83/// assert_eq!(string_is_subset("oH, well", "Hello, world!"), true);
84/// assert_eq!(string_is_subset("MMM", "Mississippi"), true);
85/// assert_eq!(string_is_subset("Hello, World!", "Hello, world!"), false);
86/// assert_eq!(string_is_subset("j", "Mississippi"), false);
87/// ```
88pub fn string_is_subset(s: &str, t: &str) -> bool {
89 let t_chars: HashSet<char> = t.chars().collect();
90 s.chars().all(|c| t_chars.contains(&c))
91}
92
93impl_named!(String);
94
95/// A trait that provides an ergonomic way to create the string specified by a [`Debug`]
96/// implementation.
97pub trait ToDebugString: Debug {
98 fn to_debug_string(&self) -> String;
99}
100
101impl<T: Debug> ToDebugString for T {
102 /// Returns the [`String`] produced by `T`s [`Debug`] implementation.
103 ///
104 /// # Examples
105 /// ```
106 /// use malachite_base::strings::ToDebugString;
107 ///
108 /// assert_eq!([1, 2, 3].to_debug_string(), "[1, 2, 3]");
109 /// assert_eq!(
110 /// [vec![2, 3], vec![], vec![4]].to_debug_string(),
111 /// "[[2, 3], [], [4]]"
112 /// );
113 /// assert_eq!(Some(5).to_debug_string(), "Some(5)");
114 /// ```
115 #[inline]
116 fn to_debug_string(&self) -> String {
117 ::alloc::format!("{self:?}")
118 }
119}
120
121/// A trait that provides an ergonomic way to create the string specified by a [`Binary`]
122/// implementation.
123pub trait ToBinaryString: Binary {
124 fn to_binary_string(&self) -> String;
125}
126
127impl<T: Binary> ToBinaryString for T {
128 /// Returns the [`String`] produced by `T`s [`Binary`] implementation.
129 ///
130 /// # Examples
131 /// ```
132 /// use malachite_base::strings::ToBinaryString;
133 ///
134 /// assert_eq!(5u64.to_binary_string(), "101");
135 /// assert_eq!((-100i16).to_binary_string(), "1111111110011100");
136 /// ```
137 #[inline]
138 fn to_binary_string(&self) -> String {
139 ::alloc::format!("{self:b}")
140 }
141}
142
143/// A trait that provides an ergonomic way to create the string specified by an [`Octal`]
144/// implementation.
145pub trait ToOctalString: Octal {
146 fn to_octal_string(&self) -> String;
147}
148
149impl<T: Octal> ToOctalString for T {
150 /// Returns the [`String`] produced by `T`s [`Octal`] implementation.
151 ///
152 /// # Examples
153 /// ```
154 /// use malachite_base::strings::ToOctalString;
155 ///
156 /// assert_eq!(50u64.to_octal_string(), "62");
157 /// assert_eq!((-100i16).to_octal_string(), "177634");
158 /// ```
159 #[inline]
160 fn to_octal_string(&self) -> String {
161 ::alloc::format!("{self:o}")
162 }
163}
164
165/// A trait that provides an ergonomic way to create the string specified by a [`LowerHex`]
166/// implementation.
167pub trait ToLowerHexString: LowerHex {
168 fn to_lower_hex_string(&self) -> String;
169}
170
171impl<T: LowerHex> ToLowerHexString for T {
172 /// Returns the [`String`] produced by `T`s [`LowerHex`] implementation.
173 ///
174 /// # Examples
175 /// ```
176 /// use malachite_base::strings::ToLowerHexString;
177 ///
178 /// assert_eq!(50u64.to_lower_hex_string(), "32");
179 /// assert_eq!((-100i16).to_lower_hex_string(), "ff9c");
180 /// ```
181 #[inline]
182 fn to_lower_hex_string(&self) -> String {
183 ::alloc::format!("{self:x}")
184 }
185}
186
187/// A trait that provides an ergonomic way to create the string specified by an [`UpperHex`]
188/// implementation.
189pub trait ToUpperHexString: UpperHex {
190 fn to_upper_hex_string(&self) -> String;
191}
192
193impl<T: UpperHex> ToUpperHexString for T {
194 /// Returns the [`String`] produced by `T`s [`UpperHex`] implementation.
195 ///
196 /// # Examples
197 /// ```
198 /// use malachite_base::strings::ToUpperHexString;
199 ///
200 /// assert_eq!(50u64.to_upper_hex_string(), "32");
201 /// assert_eq!((-100i16).to_upper_hex_string(), "FF9C");
202 /// ```
203 #[inline]
204 fn to_upper_hex_string(&self) -> String {
205 ::alloc::format!("{self:X}")
206 }
207}
208
209/// Generates [`String`]s, given an iterator that generates `Vec<char>`s.
210///
211/// This `struct` is created by [`strings_from_char_vecs`]; see its documentation for more.
212#[derive(Clone, Debug)]
213pub struct StringsFromCharVecs<I: Iterator<Item = Vec<char>>> {
214 css: I,
215}
216
217impl<I: Iterator<Item = Vec<char>>> Iterator for StringsFromCharVecs<I> {
218 type Item = String;
219
220 #[inline]
221 fn next(&mut self) -> Option<String> {
222 self.css.next().map(|cs| cs.into_iter().collect())
223 }
224}
225
226/// Generates [`String`]s, given an iterator that generates `Vec<char>`s.
227///
228/// The elements appear in the same order as they do in the given iterator, but as [`String`]s.
229///
230/// The output length is `css.count()`.
231///
232/// # Examples
233/// ```
234/// use itertools::Itertools;
235/// use malachite_base::strings::strings_from_char_vecs;
236///
237/// let ss =
238/// &strings_from_char_vecs([vec!['a', 'b'], vec!['c', 'd']].iter().cloned()).collect_vec();
239/// assert_eq!(
240/// ss.iter().map(|cs| cs.as_str()).collect_vec().as_slice(),
241/// &["ab", "cd"]
242/// );
243/// ```
244#[inline]
245pub const fn strings_from_char_vecs<I: Iterator<Item = Vec<char>>>(
246 css: I,
247) -> StringsFromCharVecs<I> {
248 StringsFromCharVecs { css }
249}
250
251/// Iterators that generate [`String`]s without repetition.
252pub mod exhaustive;
253#[cfg(feature = "random")]
254/// Iterators that generate [`String`]s randomly.
255pub mod random;