prefixmatches.nim 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. let L = s.len
  21. # check for prefix/contains:
  22. while i < L:
  23. if s[i] == '_': inc i
  24. if i < L and eq(s[i], p[0]):
  25. var ii = i+1
  26. var jj = 1
  27. while ii < L and jj < p.len:
  28. if p[jj] == '_': inc jj
  29. if s[ii] == '_': inc ii
  30. if not eq(s[ii], p[jj]): break
  31. inc ii
  32. inc jj
  33. if jj >= p.len:
  34. if i == 0: return PrefixMatch.Prefix
  35. else: return PrefixMatch.Substr
  36. inc i
  37. # check for abbrev:
  38. if eq(s[0], p[0]):
  39. i = 1
  40. var j = 1
  41. while i < s.len:
  42. if i < s.len-1 and s[i] == '_':
  43. if j < p.len and eq(p[j], s[i+1]): inc j
  44. else: return PrefixMatch.None
  45. if i < s.len and s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}:
  46. if j < p.len and eq(p[j], s[i]): inc j
  47. else: return PrefixMatch.None
  48. inc i
  49. if j >= p.len:
  50. return PrefixMatch.Abbrev
  51. else:
  52. return PrefixMatch.None
  53. return PrefixMatch.None
  54. when isMainModule:
  55. import macros
  56. macro check(val, body: untyped): untyped =
  57. result = newStmtList()
  58. expectKind body, nnkStmtList
  59. for b in body:
  60. expectKind b, nnkPar
  61. expectLen b, 2
  62. let p = b[0]
  63. let s = b[1]
  64. result.add quote do:
  65. echo prefixMatch(`p`, `s`) == `val`
  66. check PrefixMatch.Prefix:
  67. ("abc", "abc")
  68. ("a", "abc")
  69. ("xyz", "X_yzzzZe")
  70. check PrefixMatch.Substr:
  71. ("b", "abc")
  72. ("abc", "fooabcabc")
  73. ("abC", "foo_AB_c")
  74. check PrefixMatch.Abbrev:
  75. ("abc", "AxxxBxxxCxxx")
  76. ("xyz", "X_yabcZe")
  77. check PrefixMatch.None:
  78. ("foobar", "afkslfjd_as")
  79. ("xyz", "X_yuuZuuZe")
  80. ("ru", "remotes")