prefixmatches.nim 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2017 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. from strutils import toLowerAscii
  10. type
  11. PrefixMatch* {.pure.} = enum
  12. None, ## no prefix detected
  13. Abbrev ## prefix is an abbreviation of the symbol
  14. Substr, ## prefix is a substring of the symbol
  15. Prefix, ## prefix does match the symbol
  16. proc prefixMatch*(p, s: string): PrefixMatch =
  17. template eq(a, b): bool = a.toLowerAscii == b.toLowerAscii
  18. if p.len > s.len: return PrefixMatch.None
  19. var i = 0
  20. # check for prefix/contains:
  21. while i < s.len:
  22. if s[i] == '_': inc i
  23. if i < s.len and eq(s[i], p[0]):
  24. var ii = i+1
  25. var jj = 1
  26. while ii < s.len and jj < p.len:
  27. if p[jj] == '_': inc jj
  28. if s[ii] == '_': inc ii
  29. if not eq(s[ii], p[jj]): break
  30. inc ii
  31. inc jj
  32. if jj >= p.len:
  33. if i == 0: return PrefixMatch.Prefix
  34. else: return PrefixMatch.Substr
  35. inc i
  36. # check for abbrev:
  37. if eq(s[0], p[0]):
  38. i = 1
  39. var j = 1
  40. while i < s.len:
  41. if i < s.len-1 and s[i] == '_':
  42. if j < p.len and eq(p[j], s[i+1]): inc j
  43. else: return PrefixMatch.None
  44. if i < s.len and s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}:
  45. if j < p.len and eq(p[j], s[i]): inc j
  46. else: return PrefixMatch.None
  47. inc i
  48. if j >= p.len:
  49. return PrefixMatch.Abbrev
  50. else:
  51. return PrefixMatch.None
  52. return PrefixMatch.None
  53. when isMainModule:
  54. import macros
  55. macro check(val, body: untyped): untyped =
  56. result = newStmtList()
  57. expectKind body, nnkStmtList
  58. for b in body:
  59. expectKind b, nnkPar
  60. expectLen b, 2
  61. let p = b[0]
  62. let s = b[1]
  63. result.add quote do:
  64. echo prefixMatch(`p`, `s`) == `val`
  65. check PrefixMatch.Prefix:
  66. ("abc", "abc")
  67. ("a", "abc")
  68. ("xyz", "X_yzzzZe")
  69. check PrefixMatch.Substr:
  70. ("b", "abc")
  71. ("abc", "fooabcabc")
  72. ("abC", "foo_AB_c")
  73. check PrefixMatch.Abbrev:
  74. ("abc", "AxxxBxxxCxxx")
  75. ("xyz", "X_yabcZe")
  76. check PrefixMatch.None:
  77. ("foobar", "afkslfjd_as")
  78. ("xyz", "X_yuuZuuZe")
  79. ("ru", "remotes")