sort.rs 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. use std::ascii::StrAsciiExt;
  2. // This is an implementation of "natural sort order". See
  3. // http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
  4. // for more information and examples. It tries to sort "9" before
  5. // "10", which makes sense to those regular human types.
  6. // It works by splitting an input string into several parts, and then
  7. // comparing based on those parts. A SortPart derives TotalOrd, so a
  8. // Vec<SortPart> will automatically have natural sorting.
  9. #[deriving(Eq, Ord, PartialEq, PartialOrd)]
  10. pub enum SortPart {
  11. Numeric(u64),
  12. Stringular(String),
  13. }
  14. impl SortPart {
  15. pub fn from_string(is_digit: bool, slice: &str) -> SortPart {
  16. if is_digit {
  17. Numeric(from_str::<u64>(slice).expect(slice))
  18. } else {
  19. Stringular(slice.to_ascii_lower())
  20. }
  21. }
  22. // The logic here is taken from my question at
  23. // http://stackoverflow.com/q/23969191/3484614
  24. pub fn split_into_parts(input: &str) -> Vec<SortPart> {
  25. let mut parts = vec![];
  26. if input.is_empty() {
  27. return parts
  28. }
  29. let mut is_digit = input.char_at(0).is_digit();
  30. let mut start = 0;
  31. for (i, c) in input.char_indices() {
  32. if is_digit != c.is_digit() {
  33. parts.push(SortPart::from_string(is_digit, input.slice(start, i)));
  34. is_digit = !is_digit;
  35. start = i;
  36. }
  37. }
  38. parts.push(SortPart::from_string(is_digit, input.slice_from(start)));
  39. parts
  40. }
  41. }