| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- use std::ascii::StrAsciiExt;
- // This is an implementation of "natural sort order". See
- // http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
- // for more information and examples. It tries to sort "9" before
- // "10", which makes sense to those regular human types.
- // It works by splitting an input string into several parts, and then
- // comparing based on those parts. A SortPart derives TotalOrd, so a
- // Vec<SortPart> will automatically have natural sorting.
- #[deriving(Eq, Ord, PartialEq, PartialOrd)]
- pub enum SortPart {
- Numeric(u64),
- Stringular(String),
- }
- impl SortPart {
- pub fn from_string(is_digit: bool, slice: &str) -> SortPart {
- if is_digit {
- // numbers too big for a u64 fall back into strings.
- match from_str::<u64>(slice) {
- Some(num) => Numeric(num),
- None => Stringular(slice.to_string()),
- }
- } else {
- Stringular(slice.to_ascii_lower())
- }
- }
- // The logic here is taken from my question at
- // http://stackoverflow.com/q/23969191/3484614
- pub fn split_into_parts(input: &str) -> Vec<SortPart> {
- let mut parts = vec![];
- if input.is_empty() {
- return parts
- }
- let mut is_digit = input.char_at(0).is_digit();
- let mut start = 0;
- for (i, c) in input.char_indices() {
- if is_digit != c.is_digit() {
- parts.push(SortPart::from_string(is_digit, input.slice(start, i)));
- is_digit = !is_digit;
- start = i;
- }
- }
- parts.push(SortPart::from_string(is_digit, input.slice_from(start)));
- parts
- }
- }
- #[test]
- fn test_numeric() {
- let bits = SortPart::split_into_parts("123456789".as_slice());
- assert!(bits == vec![ Numeric(123456789) ]);
- }
- #[test]
- fn test_stringular() {
- let bits = SortPart::split_into_parts("toothpaste".as_slice());
- assert!(bits == vec![ Stringular("toothpaste".to_string()) ]);
- }
- #[test]
- fn test_empty() {
- let bits = SortPart::split_into_parts("".as_slice());
- assert!(bits == vec![]);
- }
- #[test]
- fn test_one() {
- let bits = SortPart::split_into_parts("123abc123".as_slice());
- assert!(bits == vec![ Numeric(123), Stringular("abc".to_string()), Numeric(123) ]);
- }
- #[test]
- fn test_two() {
- let bits = SortPart::split_into_parts("final version 3.pdf".as_slice());
- assert!(bits == vec![ Stringular("final version ".to_string()), Numeric(3), Stringular(".pdf".to_string()) ]);
- }
- #[test]
- fn test_huge_number() {
- let bits = SortPart::split_into_parts("9999999999999999999999999999999999999999999999999999999".as_slice());
- assert!(bits == vec![ Stringular("9999999999999999999999999999999999999999999999999999999".to_string()) ]);
- }
- #[test]
- fn test_case() {
- let bits = SortPart::split_into_parts("123ABC123".as_slice());
- assert!(bits == vec![ Numeric(123), Stringular("abc".to_string()), Numeric(123) ]);
- }
|