Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from functools import cmp_to_key
- #from source/blender/blenlib/intern/string.c/BLI_strcasecmp_natural for Blender 4.1.1
- def BLI_strcasecmp_natural(s1, s2):
- #there's no dedicated str.compare function in Python
- def strcmp(s1, s2):
- if s1 < s2:
- return -1
- elif s1 > s2:
- return 1
- else:
- return 0
- #compare number on the left size of the string
- def left_number_strcmp(s1, s2, tiebreaker2):
- p1 = 0
- p2 = 0
- numdigit = 0
- numzero1 = 0
- numzero2 = 0
- #count and skip leading zeros
- while s1[p1] == '0':
- p1 += 1
- numzero1 += 1
- while s2[p2] == '0':
- p2 += 1
- numzero2 += 1
- #find number of consecutive digits
- while True:
- if s1[p1+numdigit].isdigit() and s2[p2+numdigit].isdigit():
- numdigit += 1
- continue
- if s1[p1+numdigit].isdigit():
- return 1 #s2 is bigger
- if s2[p2+numdigit].isdigit():
- return -1 #s1 is bigger
- break
- #same number of digits, compare size of number
- if numdigit > 0:
- compare = strcmp(s1[p1:p1+numdigit], s2[p2:p1+numdigit])
- if compare != 0:
- return compare
- #use number of leading zeros as tie breaker if still equal
- if tiebreaker2[0] == 0:
- if numzero1 > numzero2:
- tiebreaker2[0] = 1
- elif numzero1 < numzero2:
- tiebreaker2[0] = -1
- return 0
- s1 += '\0'
- s2 += '\0'
- d1 = 0
- d2 = 0
- c1 = None
- c2 = None
- tiebreaker = 0
- #if both chars are numeric, to a left_number_strcmp().
- #then increase string deltas as long they are
- #numeric, else do a tolower and char compare
- while True:
- if s1[d1].isdigit() and s2[d2].isdigit():
- tiebreaker2 = [tiebreaker]
- numcompare = left_number_strcmp(s1[d1:], s2[d2:], tiebreaker2)
- tiebreaker = tiebreaker2[0]
- if numcompare != 0:
- return numcompare
- #Some wasted work here, left_number_strcmp already consumes at least some digits.
- d1 += 1
- while s1[d1].isdigit():
- d1 += 1
- d2 += 1
- while s2[d2].isdigit():
- d2 += 1
- #Test for end of strings first so that shorter strings are ordered in front.
- if '\0' in [s1[d1], s2[d2]]:
- break
- c1 = s1[d1].lower()
- c2 = s2[d2].lower()
- if c1 == c2:
- #Continue iteration
- pass
- #Check for '.' so "foo.bar" comes before "foo 1.bar".
- elif c1 == '.':
- return -1
- elif c2 == '.':
- return 1
- elif c1 < c2:
- return -1
- elif c1 > c2:
- return 1
- d1 += 1
- d2 += 1
- if tiebreaker != 0:
- return tiebreaker
- #we might still have a different string because of lower/upper case, in
- #that case fall back to regular string comparison
- return strcmp(s1, s2)
- print(sorted(["a", "A", "c", "b", "d", "foo.bar", "foo 1.bar", "a.00", "a.001", "a.002", "a.000"], key=cmp_to_key(BLI_strcasecmp_natural)))
Advertisement
Add Comment
Please, Sign In to add comment