diff options
| author | Yuki Okushi <huyuumi.dev@gmail.com> | 2020-07-29 09:24:17 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-29 09:24:17 +0900 |
| commit | 6968b75bd0524915d3fcf6b201b41827d4695603 (patch) | |
| tree | 28c242417d38f01677cb0d1a66e616d71cb2fdaf | |
| parent | 157975c6c40b02e56e931617f1d6c8148bc7d2bd (diff) | |
| parent | 6e9dc7d9ff806eb3a0b99ffd10892dac8e6f9739 (diff) | |
| download | rust-6968b75bd0524915d3fcf6b201b41827d4695603.tar.gz rust-6968b75bd0524915d3fcf6b201b41827d4695603.zip | |
Rollup merge of #74707 - matklad:split_once, r=dtolnay
Add str::[r]split_once
This is useful for quick&dirty parsing of key: value config pairs. Used a bunch in Cargo and rust-analyzer:
* https://github.com/rust-lang/cargo/search?q=splitn%282&unscoped_q=splitn%282
* https://github.com/rust-analyzer/rust-analyzer/search?q=split_delim&unscoped_q=split_delim
In theory, once const-generics are done, this functionality could be achieved without a dedicated method with
```rust
match s.splitn(delimier, 2).collect_array::<2>() {
Some([prefix, suffix]) => todo!(),
None => todo!(),
}
```
Even in that world, having a dedicated method seems clearer on the intention.
I am not sure about naming -- this is something I've just came up with yesterday, I don't know off the top of my head analogs in other languages.
If T-libs thinks this is a reasonable API to have, I'll open a tracking issue and add more thorough tests.
| -rw-r--r-- | library/alloc/tests/lib.rs | 1 | ||||
| -rw-r--r-- | library/alloc/tests/str.rs | 24 | ||||
| -rw-r--r-- | library/core/src/str/mod.rs | 41 |
3 files changed, 66 insertions, 0 deletions
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index e2dc816b015..fa20a466715 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -6,6 +6,7 @@ #![feature(map_first_last)] #![feature(new_uninit)] #![feature(pattern)] +#![feature(str_split_once)] #![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index eee98d45340..b20cf076aca 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1319,6 +1319,30 @@ fn test_rsplitn() { } #[test] +fn test_split_once() { + assert_eq!("".split_once("->"), None); + assert_eq!("-".split_once("->"), None); + assert_eq!("->".split_once("->"), Some(("", ""))); + assert_eq!("a->".split_once("->"), Some(("a", ""))); + assert_eq!("->b".split_once("->"), Some(("", "b"))); + assert_eq!("a->b".split_once("->"), Some(("a", "b"))); + assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c"))); + assert_eq!("---".split_once("--"), Some(("", "-"))); +} + +#[test] +fn test_rsplit_once() { + assert_eq!("".rsplit_once("->"), None); + assert_eq!("-".rsplit_once("->"), None); + assert_eq!("->".rsplit_once("->"), Some(("", ""))); + assert_eq!("a->".rsplit_once("->"), Some(("a", ""))); + assert_eq!("->b".rsplit_once("->"), Some(("", "b"))); + assert_eq!("a->b".rsplit_once("->"), Some(("a", "b"))); + assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c"))); + assert_eq!("---".rsplit_once("--"), Some(("-", ""))); +} + +#[test] fn test_split_whitespace() { let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n"; let words: Vec<&str> = data.split_whitespace().collect(); diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 790ec4bd24f..9d7e38d0e18 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -3610,6 +3610,47 @@ impl str { RSplitN(self.splitn(n, pat).0) } + /// Splits the string on the first occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_once)] + /// + /// assert_eq!("cfg".split_once('='), None); + /// assert_eq!("cfg=foo".split_once('='), Some(("cfg", "foo"))); + /// assert_eq!("cfg=foo=bar".split_once('='), Some(("cfg", "foo=bar"))); + /// ``` + #[unstable(feature = "str_split_once", reason = "newly added", issue = "74773")] + #[inline] + pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> { + let (start, end) = delimiter.into_searcher(self).next_match()?; + Some((&self[..start], &self[end..])) + } + + /// Splits the string on the last occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_once)] + /// + /// assert_eq!("cfg".rsplit_once('='), None); + /// assert_eq!("cfg=foo".rsplit_once('='), Some(("cfg", "foo"))); + /// assert_eq!("cfg=foo=bar".rsplit_once('='), Some(("cfg=foo", "bar"))); + /// ``` + #[unstable(feature = "str_split_once", reason = "newly added", issue = "74773")] + #[inline] + pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + let (start, end) = delimiter.into_searcher(self).next_match_back()?; + Some((&self[..start], &self[end..])) + } + /// An iterator over the disjoint matches of a pattern within the given string /// slice. /// |
