-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Add APIs for case folding to the standard library #154742
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
626d1ab
21a57cb
6584161
db01ed4
274ddfa
ee40444
da14011
1ec2ee9
ee7f3dd
e6d5e95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -659,6 +659,108 @@ impl str { | |
| s | ||
| } | ||
|
|
||
| /// Returns the case-folded equivalent of this string slice, as a new [`String`]. | ||
| /// | ||
| /// Case folding is a transformation, mostly matching lowercase, that is meant to be used | ||
| /// for case-insensitive string comparisons. Case-folded strings should not usually | ||
| /// be exposed directly to users. | ||
| /// | ||
| /// For the precise specification of case folding, see | ||
| /// [Chapter 3 (Conformance)](https://www.unicode.org/versions/latest/core-spec/chapter-3/#G63737) | ||
| /// of the Unicode standard. | ||
| /// | ||
| /// Since some characters can expand into multiple characters when case folding, | ||
| /// this function returns a [`String`] instead of modifying the parameter in-place. | ||
| /// | ||
| /// No [normalization] (e.g. NFC) is performed, so visually and semantically identical strings | ||
| /// might still casefold differently. For example, `"Å"` (U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE) | ||
| /// is considered distinct from `"Å"` (A followed by U+030A COMBINING RING ABOVE), | ||
| /// even though Unicode considers them canonically equivalent. | ||
| /// | ||
| /// Like [`char::to_casefold_unnormalized()`] this method does not handle language-specific | ||
| /// casing, like Turkish and Azeri I/ı/İ/i. See that method's documentation | ||
| /// for more information. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// Basic usage: | ||
| /// | ||
| /// ``` | ||
| /// #![feature(casefold)] | ||
| /// let s0 = "HELLO"; | ||
| /// let s1 = "Hello"; | ||
| /// | ||
| /// assert_eq!(s0.to_casefold_unnormalized(), s1.to_casefold_unnormalized()); | ||
| /// assert_eq!(s0.to_casefold_unnormalized(), "hello") | ||
| /// ``` | ||
| /// | ||
| /// Scripts without case are not changed: | ||
| /// | ||
| /// ``` | ||
| /// #![feature(casefold)] | ||
| /// let new_year = "农历新年"; | ||
| /// | ||
| /// assert_eq!(new_year, new_year.to_casefold_unnormalized()); | ||
| /// ``` | ||
| /// | ||
| /// One character can become multiple: | ||
| /// | ||
| /// ``` | ||
| /// #![feature(casefold)] | ||
| /// let s0 = "TSCHÜẞ"; | ||
| /// let s1 = "TSCHÜSS"; | ||
| /// let s2 = "tschüß"; | ||
| /// | ||
| /// assert_eq!(s0.to_casefold_unnormalized(), s1.to_casefold_unnormalized()); | ||
| /// assert_eq!(s0.to_casefold_unnormalized(), s2.to_casefold_unnormalized()); | ||
| /// assert_eq!(s0.to_casefold_unnormalized(), "tschüss"); | ||
| /// ``` | ||
| /// | ||
| /// No NFC [normalization] is performed: | ||
| /// | ||
| /// ```rust | ||
| /// #![feature(casefold)] | ||
| /// // These two strings are visually and semantically identical... | ||
| /// let comp = "Å"; | ||
| /// let decomp = "Å"; | ||
| /// | ||
| /// // ... but not codepoint-for-codepoint equal. | ||
| /// assert_eq!(comp, "\u{C5}"); | ||
| /// assert_eq!(decomp, "A\u{030A}"); | ||
| /// | ||
| /// // Their case-foldings are likewise unequal: | ||
| /// assert_eq!(comp.to_casefold_unnormalized(), "\u{E5}"); | ||
| /// assert_eq!(decomp.to_casefold_unnormalized(), "a\u{030A}"); | ||
| /// ``` | ||
| /// | ||
| /// [normalization]: https://www.unicode.org/faq/normalization | ||
| #[cfg(not(no_global_oom_handling))] | ||
| #[rustc_allow_incoherent_impl] | ||
| #[must_use = "this returns the case-folded string as a new String, \ | ||
| without modifying the original"] | ||
| #[unstable(feature = "casefold", issue = "154742")] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Jules-Bertholet Here (and in other
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, sorry. The tracking issue already exists at #157000, I just copy-pasted the wrong number
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| pub fn to_casefold_unnormalized(&self) -> String { | ||
| // SAFETY: `to_ascii_lowercase` preserves ASCII bytes, so the converted | ||
| // prefix remains valid UTF-8. | ||
| let (mut s, rest) = unsafe { convert_while_ascii(self, u8::to_ascii_lowercase) }; | ||
|
|
||
| for c in rest.chars() { | ||
| match conversions::to_casefold(c) { | ||
| [a, '\0', _] => s.push(a), | ||
| [a, b, '\0'] => { | ||
| s.push(a); | ||
| s.push(b); | ||
| } | ||
| [a, b, c] => { | ||
| s.push(a); | ||
| s.push(b); | ||
| s.push(c); | ||
| } | ||
| } | ||
| } | ||
| s | ||
| } | ||
|
|
||
| /// Converts a [`Box<str>`] into a [`String`] without copying or allocating. | ||
| /// | ||
| /// # Examples | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.