Skip to main content

phpify/string/
explode.rs

1// Copyright (c) 2020 DarkWeb Design
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16// SOFTWARE.
17
18// https://www.php.net/manual/en/ref.strings.php
19
20/// Split a string by a string.
21///
22/// # Description
23///
24/// Returns an vec of strings, each of which is a substring of string formed by splitting it on
25/// boundaries formed by the string delimiter.
26///
27/// # Parameters
28///
29/// **limit**
30///
31/// If limit is set and positive, the returned vec will contain a maximum of limit elements with the
32/// last element containing the rest of string.
33///
34/// If the limit parameter is negative, all components except the last -limit are returned.
35///
36/// If the limit parameter is zero, then this is treated as 1.
37///
38/// # Examples
39///
40/// Example #1 explode() examples
41///
42/// ```
43/// use phpify::string::explode;
44///
45/// let pizza = "piece1 piece2 piece3 piece4 piece5 piece6";
46/// let pieces = explode(" ", pizza, std::isize::MAX).unwrap();
47///
48/// assert_eq!(pieces, ["piece1", "piece2", "piece3", "piece4", "piece5", "piece6"]);
49/// ```
50///
51/// ```
52/// use phpify::string::explode;
53///
54/// let data = "foo:*:1023:1000::/home/foo:/bin/sh";
55/// let elements = explode(":", data, std::isize::MAX).unwrap();
56///
57/// assert_eq!(elements[0], "foo".to_string());
58/// assert_eq!(elements[1], "*".to_string());
59/// ```
60///
61/// Example #2 explode() return examples
62///
63/// ```
64/// use phpify::string::explode;
65///
66/// let input1 = "hello";
67/// let input2 = "hello,there";
68/// let input3 = ",";
69///
70/// assert_eq!(explode(",", input1, std::isize::MAX).unwrap(), ["hello"]);
71/// assert_eq!(explode(",", input2, std::isize::MAX).unwrap(), ["hello", "there"]);
72/// assert_eq!(explode(",", input3, std::isize::MAX).unwrap(), ["", ""]);
73/// ```
74///
75/// Example #3 limit parameter examples
76///
77/// ```
78/// use phpify::string::explode;
79///
80/// let str = "one|two|three|four";
81///
82/// assert_eq!(explode("|", str, 2).unwrap(), ["one", "two|three|four"]);
83/// assert_eq!(explode("|", str, -1).unwrap(), ["one", "two", "three"]);
84/// ```
85pub fn explode<D, S>(delimiter: D, string: S, limit: isize) -> Option<Vec<String>>
86    where
87        D: AsRef<str>,
88        S: AsRef<str> {
89
90    let delimiter = delimiter.as_ref();
91    let string = string.as_ref();
92
93    if delimiter.is_empty() {
94        return None;
95    }
96
97    if limit == 0 || limit == 1 {
98        return Some(vec![string.to_string()]);
99    }
100
101    let vec: Vec<String> = string.split(delimiter).map(String::from).collect();
102    let vec_length = vec.len() as isize;
103
104    if limit > vec_length {
105        return Some(vec);
106    }
107
108    if limit > 0 {
109        let (left, right) = vec.split_at(limit as usize - 1);
110        let mut vec = left.to_vec();
111        vec.push(right.join(delimiter));
112
113        return Some(vec);
114    }
115
116    if limit < 0 {
117        if limit <= (0 - vec_length) {
118            return Some(vec![]);
119        }
120        let (left, _right) = vec.split_at((vec_length + limit) as usize);
121        let vec = left.to_vec();
122
123        return Some(vec);
124    }
125
126    Some(vec)
127}
128
129#[cfg(test)]
130mod tests {
131    use crate::string::explode;
132
133    #[test]
134    fn test() {
135        assert_eq!(explode("|", "one|two|three", 3), Some(vec!["one".to_string(), "two".to_string(), "three".to_string()]));
136        assert_eq!(explode("|", "one|two|three", 1), Some(vec!["one|two|three".to_string()]));
137        assert_eq!(explode("|", "one|two|three", 2), Some(vec!["one".to_string(), "two|three".to_string()]));
138        assert_eq!(explode("|", "one|two|three", -1), Some(vec!["one".to_string(), "two".to_string()]));
139        assert_eq!(explode("|", "one|two|three", -3), Some(vec![]));
140        assert_eq!(explode(",", "one|two|three", 1), Some(vec!["one|two|three".to_string()]));
141        assert_eq!(explode("", "one|two|three", 3), None);
142    }
143}