naturalCompare.js.flow 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. // @flow strict
  2. /**
  3. * Returns a number indicating whether a reference string comes before, or after,
  4. * or is the same as the given string in natural sort order.
  5. *
  6. * See: https://en.wikipedia.org/wiki/Natural_sort_order
  7. *
  8. */
  9. export default function naturalCompare(aStr: string, bStr: string): number {
  10. let aIdx = 0;
  11. let bIdx = 0;
  12. while (aIdx < aStr.length && bIdx < bStr.length) {
  13. let aChar = aStr.charCodeAt(aIdx);
  14. let bChar = bStr.charCodeAt(bIdx);
  15. if (isDigit(aChar) && isDigit(bChar)) {
  16. let aNum = 0;
  17. do {
  18. ++aIdx;
  19. aNum = aNum * 10 + aChar - DIGIT_0;
  20. aChar = aStr.charCodeAt(aIdx);
  21. } while (isDigit(aChar) && aNum > 0);
  22. let bNum = 0;
  23. do {
  24. ++bIdx;
  25. bNum = bNum * 10 + bChar - DIGIT_0;
  26. bChar = bStr.charCodeAt(bIdx);
  27. } while (isDigit(bChar) && bNum > 0);
  28. if (aNum < bNum) {
  29. return -1;
  30. }
  31. if (aNum > bNum) {
  32. return 1;
  33. }
  34. } else {
  35. if (aChar < bChar) {
  36. return -1;
  37. }
  38. if (aChar > bChar) {
  39. return 1;
  40. }
  41. ++aIdx;
  42. ++bIdx;
  43. }
  44. }
  45. return aStr.length - bStr.length;
  46. }
  47. const DIGIT_0 = 48;
  48. const DIGIT_9 = 57;
  49. function isDigit(code: number): boolean {
  50. return !isNaN(code) && DIGIT_0 <= code && code <= DIGIT_9;
  51. }