Skip to content

Commit e04bf2e

Browse files
committed
✨ v1.0.0
0 parents  commit e04bf2e

5 files changed

Lines changed: 221 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Cargo.lock
2+
target/*

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "split-every"
3+
version = "1.0.0"
4+
edition = "2021"
5+
authors = ["JumperBot_"]
6+
description = "Split for every n occurences of a pattern iteratively!"
7+
license = "MIT"
8+
keywords = ["split", "string", "iterator", "pattern", "occurences"]
9+
categories = ["development-tools", "text-processing", "visualization", "parsing", "value-formatting"]
10+
repository = "https://github.com/JumperBot/split-every/"
11+
12+
[lib]
13+
path = "src/lib.rs"
14+
test = true
15+
doctest = true
16+
doc = true
17+
crate-type = ["lib"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 JumperBot_
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<div align="center">
2+
3+
# split-every
4+
5+
![crates.io version](https://img.shields.io/crates/v/split-every.svg?label=release)
6+
![github.com forks](https://img.shields.io/github/forks/JumperBot/split-every)
7+
![github.com stars](https://img.shields.io/github/stars/JumperBot/split-every)
8+
![crates.io downloads](https://img.shields.io/crates/d/split-every.svg?label=downloads)
9+
10+
</div>
11+
12+
---
13+
14+
```rust
15+
use split_every::{SplitEveryImpl, SplitEvery};
16+
// This prints: "Oh hi there"
17+
// "I don't really"
18+
// "know what to"
19+
// "say".
20+
let mut splitter: SplitEvery =
21+
"Oh hi there I don't really know what to say".split_every_n_of_str(" ", 3);
22+
println!("{}", splitter.next().unwrap());
23+
println!("{}", splitter.next().unwrap());
24+
println!("{}", splitter.next().unwrap());
25+
println!("{}", splitter.next().unwrap());
26+
```
27+
28+
---
29+
30+
## ✨ Split For Every N Occurences Of A Pattern Iteratively
31+
32+
This crate **helps you** split a `string` for every `n` occurences of a `pattern`.
33+
It contains an exclusive `iterator`.
34+
35+
---
36+
37+
## 📄 Licensing
38+
39+
`split-every` is licensed under the [`MIT LICENSE`](./LICENSE); This is the [`summarization`](https://choosealicense.com/licenses/mit/).

src/lib.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//! Split for every n occurences of a pattern iteratively.
2+
//! This crate **helps you** split a `string` for every `n` occurences of a `pattern`.
3+
//! It contains an exclusive `iterator`.
4+
//!
5+
//! # Examples
6+
//!
7+
//! ```rust
8+
//! use split_every::{SplitEveryImpl, SplitEvery};
9+
//! // This prints: "Oh hi there"
10+
//! // "I don't really"
11+
//! // "know what to"
12+
//! // "say".
13+
//! let mut splitter: SplitEvery =
14+
//! "Oh hi there I don't really know what to say".split_every_n_of_str(" ", 3);
15+
//! println!("{}", splitter.next().unwrap());
16+
//! println!("{}", splitter.next().unwrap());
17+
//! println!("{}", splitter.next().unwrap());
18+
//! println!("{}", splitter.next().unwrap());
19+
//! ```
20+
21+
/// A trait containing all `string` split-every functions.
22+
pub trait SplitEveryImpl: AsRef<str> {
23+
/// This splits a `string` every `n` times a `string` is found.
24+
/// This splits exclusively.
25+
/// The `string` must be `utf8-encoded`.
26+
#[must_use]
27+
fn split_every_n_of_str<'a>(&'a self, pat: &'a str, n: usize) -> SplitEvery<'a> {
28+
assert!(n > 0, "n must be greater than 0");
29+
SplitEvery {
30+
inner: self.as_ref(),
31+
pat: Pattern::Str(pat),
32+
n,
33+
index: 0,
34+
}
35+
}
36+
37+
/// This splits a `string` every `n` times a `char` is found.
38+
/// This splits exclusively.
39+
/// The `string` must be `utf8-encoded`.
40+
#[must_use]
41+
fn split_every_n_of_char(&self, pat: char, n: usize) -> SplitEvery<'_> {
42+
assert!(n > 0, "n must be greater than 0");
43+
SplitEvery {
44+
inner: self.as_ref(),
45+
pat: Pattern::Ch(pat),
46+
n,
47+
index: 0,
48+
}
49+
}
50+
}
51+
52+
impl<T: AsRef<str>> SplitEveryImpl for T {}
53+
54+
/// A convinient substitution to `std::str::pattern::Pattern`.
55+
enum Pattern<'a> {
56+
Str(&'a str),
57+
Ch(char),
58+
}
59+
60+
impl<'a> Pattern<'a> {
61+
/// A convinient `len` method.
62+
fn len(&self) -> usize {
63+
match self {
64+
Self::Str(inner) => inner.len(),
65+
Self::Ch(inner) => inner.len_utf8(),
66+
}
67+
}
68+
}
69+
70+
/// An `Iterator` struct for splitting a `string` every `n` occurences of a `pattern`.
71+
pub struct SplitEvery<'a> {
72+
inner: &'a str,
73+
pat: Pattern<'a>,
74+
n: usize,
75+
index: usize,
76+
}
77+
78+
impl<'a> Iterator for SplitEvery<'a> {
79+
type Item = &'a str;
80+
81+
fn next(&mut self) -> Option<Self::Item> {
82+
if self.index == self.inner.len() {
83+
return None;
84+
}
85+
let haystack: &str = unsafe { self.inner.get_unchecked(self.index..) };
86+
let mut len: usize = 0;
87+
for ind in 0..self.n {
88+
let haystack: &str = unsafe { haystack.get_unchecked(len..) };
89+
if let Some(byte_ind) = match self.pat {
90+
Pattern::Str(inner) => haystack.find(inner),
91+
Pattern::Ch(inner) => haystack.find(inner),
92+
} {
93+
len = unsafe { len.unchecked_add(byte_ind).unchecked_add(self.pat.len()) };
94+
continue;
95+
}
96+
if ind == 0 {
97+
self.index = self.inner.len();
98+
return Some(haystack);
99+
}
100+
break;
101+
}
102+
self.index = unsafe { self.index.unchecked_add(len) };
103+
Some(unsafe { haystack.get_unchecked(..len.unchecked_sub(self.pat.len())) })
104+
}
105+
}
106+
107+
#[test]
108+
fn test() {
109+
let mut splitter: SplitEvery = "oh oh oh oh oh".split_every_n_of_str(" ", 2);
110+
assert_eq!(splitter.next(), Some("oh oh"));
111+
assert_eq!(splitter.next(), Some("oh oh"));
112+
assert_eq!(splitter.next(), Some("oh"));
113+
assert_eq!(splitter.next(), None);
114+
assert_eq!(splitter.next(), None);
115+
116+
let mut splitter: SplitEvery = "oboooobobobobob".split_every_n_of_char('o', 3);
117+
assert_eq!(splitter.next(), Some("obo"));
118+
assert_eq!(splitter.next(), Some("oob"));
119+
assert_eq!(splitter.next(), Some("bobob"));
120+
assert_eq!(splitter.next(), Some("b"));
121+
assert_eq!(splitter.next(), None);
122+
assert_eq!(splitter.next(), None);
123+
124+
let mut splitter: SplitEvery = "hhhahahahaha".split_every_n_of_char('h', 1);
125+
assert_eq!(splitter.next(), Some(""));
126+
assert_eq!(splitter.next(), Some(""));
127+
assert_eq!(splitter.next(), Some(""));
128+
assert_eq!(splitter.next(), Some("a"));
129+
assert_eq!(splitter.next(), Some("a"));
130+
assert_eq!(splitter.next(), Some("a"));
131+
assert_eq!(splitter.next(), Some("a"));
132+
assert_eq!(splitter.next(), Some("a"));
133+
assert_eq!(splitter.next(), None);
134+
assert_eq!(splitter.next(), None);
135+
136+
let mut splitter: SplitEvery =
137+
"Oh hi there I don't really know what to say".split_every_n_of_str(" ", 3);
138+
assert_eq!(splitter.next().unwrap(), "Oh hi there");
139+
assert_eq!(splitter.next().unwrap(), "I don't really");
140+
assert_eq!(splitter.next().unwrap(), "know what to");
141+
assert_eq!(splitter.next().unwrap(), "say");
142+
}

0 commit comments

Comments
 (0)