sort.rs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. // numbers too big for a u64 fall back into strings.
  18. match from_str::<u64>(slice) {
  19. Some(num) => Numeric(num),
  20. None => Stringular(slice.to_string()),
  21. }
  22. } else {
  23. Stringular(slice.to_ascii_lower())
  24. }
  25. }
  26. // The logic here is taken from my question at
  27. // http://stackoverflow.com/q/23969191/3484614
  28. pub fn split_into_parts(input: &str) -> Vec<SortPart> {
  29. let mut parts = vec![];
  30. if input.is_empty() {
  31. return parts
  32. }
  33. let mut is_digit = input.char_at(0).is_digit();
  34. let mut start = 0;
  35. for (i, c) in input.char_indices() {
  36. if is_digit != c.is_digit() {
  37. parts.push(SortPart::from_string(is_digit, input.slice(start, i)));
  38. is_digit = !is_digit;
  39. start = i;
  40. }
  41. }
  42. parts.push(SortPart::from_string(is_digit, input.slice_from(start)));
  43. parts
  44. }
  45. }
  46. #[test]
  47. fn test_numeric() {
  48. let bits = SortPart::split_into_parts("123456789".as_slice());
  49. assert!(bits == vec![ Numeric(123456789) ]);
  50. }
  51. #[test]
  52. fn test_stringular() {
  53. let bits = SortPart::split_into_parts("toothpaste".as_slice());
  54. assert!(bits == vec![ Stringular("toothpaste".to_string()) ]);
  55. }
  56. #[test]
  57. fn test_empty() {
  58. let bits = SortPart::split_into_parts("".as_slice());
  59. assert!(bits == vec![]);
  60. }
  61. #[test]
  62. fn test_one() {
  63. let bits = SortPart::split_into_parts("123abc123".as_slice());
  64. assert!(bits == vec![ Numeric(123), Stringular("abc".to_string()), Numeric(123) ]);
  65. }
  66. #[test]
  67. fn test_two() {
  68. let bits = SortPart::split_into_parts("final version 3.pdf".as_slice());
  69. assert!(bits == vec![ Stringular("final version ".to_string()), Numeric(3), Stringular(".pdf".to_string()) ]);
  70. }
  71. #[test]
  72. fn test_huge_number() {
  73. let bits = SortPart::split_into_parts("9999999999999999999999999999999999999999999999999999999".as_slice());
  74. assert!(bits == vec![ Stringular("9999999999999999999999999999999999999999999999999999999".to_string()) ]);
  75. }
  76. #[test]
  77. fn test_case() {
  78. let bits = SortPart::split_into_parts("123ABC123".as_slice());
  79. assert!(bits == vec![ Numeric(123), Stringular("abc".to_string()), Numeric(123) ]);
  80. }