From be13a03a9d0d8cc4439063abf34ef3ad24268469 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 19 Nov 2021 17:51:36 +0000 Subject: [PATCH 1/3] str: Implement str::strip_newline --- library/core/src/lib.rs | 1 + library/core/src/str/mod.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4a64e2e2d102d..67bf65f81c559 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -174,6 +174,7 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(let_else)] #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(min_specialization)] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index cd5ed35be79ba..5580da5a4ca62 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1833,6 +1833,43 @@ impl str { self.trim_end_matches(|c: char| c.is_whitespace()) } + /// Returns a string slice with any one trailing newline removed. + /// + /// 'Newline' is precisely a newline character (`0xA`), perhaps + /// preceded by a carriage return (`0xD`). I.e., `'\r\n'` or + /// `'\n'`. (This is the same definition as used by [`str::lines`] + /// and [`std::io::BufRead::lines`].) + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_newline)] + /// use std::fmt::Write as _; + /// + /// assert_eq!("Text", "Text".trim_newline()); + /// assert_eq!("Text", "Text\n".trim_newline()); + /// assert_eq!("Text", "Text\r\n".trim_newline()); + /// assert_eq!("Text\r", "Text\r".trim_newline()); + /// assert_eq!("Text\n", "Text\n\n".trim_newline()); + /// + /// let mut s = String::new(); + /// writeln!(s, " Hi! ").unwrap(); + /// assert_eq!(" Hi! ", s.trim_newline()); + /// assert_eq!(" Hi! ", s.trim_newline().trim_newline()); + /// ``` + /// + /// [`std::io::BufRead::lines`]: ../std/io/trait.BufRead.html#method.lines + #[inline] + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] + #[unstable(feature = "trim_newline", issue = "none")] + pub fn trim_newline(&self) -> &str { + let s = self; + let Some(s) = s.strip_suffix('\n') else { return s }; + let Some(s) = s.strip_suffix('\r') else { return s }; + s + } + /// Returns a string slice with leading whitespace removed. /// /// 'Whitespace' is defined according to the terms of the Unicode Derived From 60cb3e6c21408a6ff4d512a6f3319c7875b31c55 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 19 Nov 2021 18:41:34 +0000 Subject: [PATCH 2/3] str::trim_newline: delinkify link to BufRead::lines Sadly there doesn't seem to be a way to do this right now. --- library/core/src/str/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 5580da5a4ca62..0cedfb14ee583 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1838,7 +1838,13 @@ impl str { /// 'Newline' is precisely a newline character (`0xA`), perhaps /// preceded by a carriage return (`0xD`). I.e., `'\r\n'` or /// `'\n'`. (This is the same definition as used by [`str::lines`] - /// and [`std::io::BufRead::lines`].) + /// and `std::io::BufRead::lines`.) + // + // Unfortunately it doesn't seem to be possible to make the reference to `lines` + // a link. This: + // [`std::io::BufRead::lines`]: ../std/io/trait.BufRead.html#method.lines + // works in `core`, but fails with a broken link error in `std`, where + // this text is incorporated due to `String`'s `Deref`. /// /// # Examples /// @@ -1857,8 +1863,6 @@ impl str { /// assert_eq!(" Hi! ", s.trim_newline()); /// assert_eq!(" Hi! ", s.trim_newline().trim_newline()); /// ``` - /// - /// [`std::io::BufRead::lines`]: ../std/io/trait.BufRead.html#method.lines #[inline] #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] From ca04e2b650545f6d0d180fc14b8307fed243a3e4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 19 Nov 2021 18:42:17 +0000 Subject: [PATCH 3/3] str::trim_newline: Add a test case demoing handling of LF-CR --- library/core/src/str/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 0cedfb14ee583..7dc8b51a04dce 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1857,6 +1857,7 @@ impl str { /// assert_eq!("Text", "Text\r\n".trim_newline()); /// assert_eq!("Text\r", "Text\r".trim_newline()); /// assert_eq!("Text\n", "Text\n\n".trim_newline()); + /// assert_eq!("Text\n\r", "Text\n\r".trim_newline()); // LF CR is not a valid newline /// /// let mut s = String::new(); /// writeln!(s, " Hi! ").unwrap();