fork download
  1. from itertools import islice, zip_longest
  2. import string
  3. from typing import Iterator, Sequence
  4.  
  5.  
  6. def sliding_window_of[T](window_length: int, iterable: Sequence[T]) -> Iterator[tuple[T, *tuple[T | None, ...]]]:
  7. assert window_length >= 1
  8. window_its = [
  9. islice(iterable, i, None, None)
  10. for i in range(window_length)
  11. ]
  12. yield from zip_longest(*window_its) # type:ignore
  13.  
  14.  
  15. def get_opts(options: str) -> list[str]:
  16. # validations
  17. if not all(opt == '/' or opt in string.ascii_lowercase for opt in options):
  18. raise ValueError("options string must be only lowercase letters or slashes")
  19.  
  20. if options.startswith('/') or options.endswith('/'):
  21. raise ValueError("must not start of end with a slash")
  22.  
  23. if any(window == ('/', '/') for window in sliding_window_of(2, options)):
  24. raise ValueError("a slash cannot be followed by another slash")
  25.  
  26. triples = sliding_window_of(3, options)
  27. opts = list[str]()
  28.  
  29. # first case is special because we need to get the left-most character
  30. match next(triples, None):
  31. case (a, '/', str(b)):
  32. opts.append(a+b)
  33. case (a, _, '/'):
  34. opts.append(a)
  35. case (a, str(b), _):
  36. opts.extend((a, b))
  37.  
  38. for triple in triples:
  39. match triple:
  40. case ('/', _, _) | (_, _, '/'):
  41. pass
  42. case (a, '/', str(b)):
  43. opts.append(a+b)
  44. case (_, str(a), _):
  45. opts.append(a)
  46.  
  47. return opts
  48.  
  49.  
  50. for opts in ["abcd/efgh/ijk", "abc//def", "invalid!chars", "/a", "b/"]:
  51. try:
  52. print(f"{opts} => {get_opts(opts)}")
  53. except ValueError as ve:
  54. print(f"{opts} => {ve!r}")
  55.  
Success #stdin #stdout 0.25s 17292KB
stdin
Standard input is empty
stdout
abcd/efgh/ijk => ['a', 'b', 'c', 'de', 'f', 'g', 'hi', 'j', 'k']
abc//def => ValueError('a slash cannot be followed by another slash')
invalid!chars => ValueError('options string must be only lowercase letters or slashes')
/a => ValueError('must not start of end with a slash')
b/ => ValueError('must not start of end with a slash')