ordering.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import re
  2. INTERFACE_NAME_REGEX = r'(^(?P<type>[^\d\.:]+)?)' \
  3. r'((?P<slot>\d+)/)?' \
  4. r'((?P<subslot>\d+)/)?' \
  5. r'((?P<position>\d+)/)?' \
  6. r'((?P<subposition>\d+)/)?' \
  7. r'((?P<id>\d+))?' \
  8. r'(:(?P<channel>\d+))?' \
  9. r'(\.(?P<vc>\d+))?' \
  10. r'(?P<remainder>.*)$'
  11. def naturalize(value, max_length, integer_places=8):
  12. """
  13. Take an alphanumeric string and prepend all integers to `integer_places` places to ensure the strings
  14. are ordered naturally. For example:
  15. site9router21
  16. site10router4
  17. site10router19
  18. becomes:
  19. site00000009router00000021
  20. site00000010router00000004
  21. site00000010router00000019
  22. :param value: The value to be naturalized
  23. :param max_length: The maximum length of the returned string. Characters beyond this length will be stripped.
  24. :param integer_places: The number of places to which each integer will be expanded. (Default: 8)
  25. """
  26. if not value:
  27. return value
  28. output = []
  29. for segment in re.split(r'(\d+)', value):
  30. if segment.isdigit():
  31. output.append(segment.rjust(integer_places, '0'))
  32. elif segment:
  33. output.append(segment)
  34. ret = ''.join(output)
  35. return ret[:max_length]
  36. def naturalize_interface(value, max_length):
  37. """
  38. Similar in nature to naturalize(), but takes into account a particular naming format adapted from the old
  39. InterfaceManager.
  40. :param value: The value to be naturalized
  41. :param max_length: The maximum length of the returned string. Characters beyond this length will be stripped.
  42. """
  43. output = ''
  44. match = re.search(INTERFACE_NAME_REGEX, value)
  45. if match is None:
  46. return value
  47. # First, we order by slot/position, padding each to four digits. If a field is not present,
  48. # set it to 9999 to ensure it is ordered last.
  49. for part_name in ('slot', 'subslot', 'position', 'subposition'):
  50. part = match.group(part_name)
  51. if part is not None:
  52. output += part.rjust(4, '0')
  53. else:
  54. output += '9999'
  55. # Append the type, if any.
  56. if match.group('type') is not None:
  57. output += match.group('type')
  58. # Append any remaining fields, left-padding to six digits each.
  59. for part_name in ('id', 'channel', 'vc'):
  60. part = match.group(part_name)
  61. if part is not None:
  62. output += part.rjust(6, '0')
  63. else:
  64. output += '......'
  65. # Finally, naturalize any remaining text and append it
  66. if match.group('remainder') is not None and len(output) < max_length:
  67. remainder = naturalize(match.group('remainder'), max_length - len(output))
  68. output += remainder
  69. return output[:max_length]