funcs_str.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Copyright 2022 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package function
  15. import (
  16. "bytes"
  17. "fmt"
  18. "github.com/lf-edge/ekuiper/pkg/api"
  19. "github.com/lf-edge/ekuiper/pkg/ast"
  20. "github.com/lf-edge/ekuiper/pkg/cast"
  21. "regexp"
  22. "strings"
  23. "unicode"
  24. "unicode/utf8"
  25. )
  26. func registerStrFunc() {
  27. builtins["concat"] = builtinFunc{
  28. fType: FuncTypeScalar,
  29. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  30. var b bytes.Buffer
  31. for _, arg := range args {
  32. b.WriteString(cast.ToStringAlways(arg))
  33. }
  34. return b.String(), true
  35. },
  36. val: func(_ api.FunctionContext, args []ast.Expr) error {
  37. if len(args) == 0 {
  38. return fmt.Errorf("The arguments should be at least one.")
  39. }
  40. for i, a := range args {
  41. if ast.IsNumericArg(a) || ast.IsTimeArg(a) || ast.IsBooleanArg(a) {
  42. return ProduceErrInfo(i, "string")
  43. }
  44. }
  45. return nil
  46. },
  47. }
  48. builtins["endswith"] = builtinFunc{
  49. fType: FuncTypeScalar,
  50. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  51. if args[0] == nil || args[1] == nil {
  52. return false, true
  53. }
  54. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  55. return strings.HasSuffix(arg0, arg1), true
  56. },
  57. val: ValidateTwoStrArg,
  58. }
  59. builtins["indexof"] = builtinFunc{
  60. fType: FuncTypeScalar,
  61. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  62. if args[0] == nil || args[1] == nil {
  63. return -1, true
  64. }
  65. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  66. return strings.Index(arg0, arg1), true
  67. },
  68. val: ValidateTwoStrArg,
  69. }
  70. builtins["length"] = builtinFunc{
  71. fType: FuncTypeScalar,
  72. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  73. arg0 := cast.ToStringAlways(args[0])
  74. return utf8.RuneCountInString(arg0), true
  75. },
  76. val: ValidateOneStrArg,
  77. }
  78. builtins["lower"] = builtinFunc{
  79. fType: FuncTypeScalar,
  80. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  81. if args[0] == nil {
  82. return nil, true
  83. }
  84. arg0 := cast.ToStringAlways(args[0])
  85. return strings.ToLower(arg0), true
  86. },
  87. val: ValidateOneStrArg,
  88. }
  89. builtins["lpad"] = builtinFunc{
  90. fType: FuncTypeScalar,
  91. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  92. if args[0] == nil {
  93. return nil, true
  94. }
  95. arg0 := cast.ToStringAlways(args[0])
  96. arg1, err := cast.ToInt(args[1], cast.STRICT)
  97. if err != nil {
  98. return err, false
  99. }
  100. return strings.Repeat(" ", arg1) + arg0, true
  101. },
  102. val: ValidateOneStrOneInt,
  103. }
  104. builtins["ltrim"] = builtinFunc{
  105. fType: FuncTypeScalar,
  106. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  107. if args[0] == nil {
  108. return nil, true
  109. }
  110. arg0 := cast.ToStringAlways(args[0])
  111. return strings.TrimLeftFunc(arg0, unicode.IsSpace), true
  112. },
  113. val: ValidateOneStrArg,
  114. }
  115. builtins["numbytes"] = builtinFunc{
  116. fType: FuncTypeScalar,
  117. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  118. arg0 := cast.ToStringAlways(args[0])
  119. return len(arg0), true
  120. },
  121. val: ValidateOneStrArg,
  122. }
  123. builtins["format_time"] = builtinFunc{
  124. fType: FuncTypeScalar,
  125. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  126. if args[0] == nil {
  127. return nil, true
  128. }
  129. arg0, err := cast.InterfaceToTime(args[0], "")
  130. if err != nil {
  131. return err, false
  132. }
  133. arg1 := cast.ToStringAlways(args[1])
  134. if s, err := cast.FormatTime(arg0, arg1); err == nil {
  135. return s, true
  136. } else {
  137. return err, false
  138. }
  139. },
  140. val: func(_ api.FunctionContext, args []ast.Expr) error {
  141. if err := ValidateLen(2, len(args)); err != nil {
  142. return err
  143. }
  144. if ast.IsNumericArg(args[0]) || ast.IsStringArg(args[0]) || ast.IsBooleanArg(args[0]) {
  145. return ProduceErrInfo(0, "datetime")
  146. }
  147. if ast.IsNumericArg(args[1]) || ast.IsTimeArg(args[1]) || ast.IsBooleanArg(args[1]) {
  148. return ProduceErrInfo(1, "string")
  149. }
  150. return nil
  151. },
  152. }
  153. builtins["regexp_matches"] = builtinFunc{
  154. fType: FuncTypeScalar,
  155. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  156. if args[0] == nil || args[1] == nil {
  157. return false, true
  158. }
  159. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  160. if matched, err := regexp.MatchString(arg1, arg0); err != nil {
  161. return err, false
  162. } else {
  163. return matched, true
  164. }
  165. },
  166. val: ValidateTwoStrArg,
  167. }
  168. builtins["regexp_replace"] = builtinFunc{
  169. fType: FuncTypeScalar,
  170. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  171. if args[0] == nil || args[1] == nil || args[2] == nil {
  172. return nil, true
  173. }
  174. arg0, arg1, arg2 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1]), cast.ToStringAlways(args[2])
  175. if re, err := regexp.Compile(arg1); err != nil {
  176. return err, false
  177. } else {
  178. return re.ReplaceAllString(arg0, arg2), true
  179. }
  180. },
  181. val: func(_ api.FunctionContext, args []ast.Expr) error {
  182. if err := ValidateLen(3, len(args)); err != nil {
  183. return err
  184. }
  185. for i := 0; i < 3; i++ {
  186. if ast.IsNumericArg(args[i]) || ast.IsTimeArg(args[i]) || ast.IsBooleanArg(args[i]) {
  187. return ProduceErrInfo(i, "string")
  188. }
  189. }
  190. return nil
  191. },
  192. }
  193. builtins["regexp_substr"] = builtinFunc{
  194. fType: FuncTypeScalar,
  195. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  196. if args[0] == nil || args[1] == nil {
  197. return nil, true
  198. }
  199. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  200. if re, err := regexp.Compile(arg1); err != nil {
  201. return err, false
  202. } else {
  203. return re.FindString(arg0), true
  204. }
  205. },
  206. val: ValidateTwoStrArg,
  207. }
  208. builtins["rpad"] = builtinFunc{
  209. fType: FuncTypeScalar,
  210. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  211. if args[0] == nil {
  212. return nil, true
  213. }
  214. arg0 := cast.ToStringAlways(args[0])
  215. arg1, err := cast.ToInt(args[1], cast.STRICT)
  216. if err != nil {
  217. return err, false
  218. }
  219. return arg0 + strings.Repeat(" ", arg1), true
  220. },
  221. val: ValidateOneStrOneInt,
  222. }
  223. builtins["rtrim"] = builtinFunc{
  224. fType: FuncTypeScalar,
  225. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  226. if args[0] == nil {
  227. return nil, true
  228. }
  229. arg0 := cast.ToStringAlways(args[0])
  230. return strings.TrimRightFunc(arg0, unicode.IsSpace), true
  231. },
  232. val: ValidateOneStrArg,
  233. }
  234. builtins["substring"] = builtinFunc{
  235. fType: FuncTypeScalar,
  236. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  237. if args[0] == nil {
  238. return nil, true
  239. }
  240. arg0 := cast.ToStringAlways(args[0])
  241. arg1, err := cast.ToInt(args[1], cast.STRICT)
  242. if err != nil {
  243. return err, false
  244. }
  245. if arg1 < 0 {
  246. return fmt.Errorf("start index must be a positive number"), false
  247. }
  248. if len(args) > 2 {
  249. arg2, err := cast.ToInt(args[2], cast.STRICT)
  250. if err != nil {
  251. return err, false
  252. }
  253. if arg2 < 0 {
  254. return fmt.Errorf("end index must be a positive number"), false
  255. }
  256. if arg1 > arg2 {
  257. return fmt.Errorf("start index must be smaller than end index"), false
  258. }
  259. if arg1 > len(arg0) {
  260. return "", true
  261. }
  262. if arg2 > len(arg0) {
  263. return arg0[arg1:], true
  264. }
  265. return arg0[arg1:arg2], true
  266. } else {
  267. if arg1 > len(arg0) {
  268. return "", true
  269. }
  270. return arg0[arg1:], true
  271. }
  272. },
  273. val: func(_ api.FunctionContext, args []ast.Expr) error {
  274. l := len(args)
  275. if l != 2 && l != 3 {
  276. return fmt.Errorf("the arguments for substring should be 2 or 3")
  277. }
  278. if ast.IsNumericArg(args[0]) || ast.IsTimeArg(args[0]) || ast.IsBooleanArg(args[0]) {
  279. return ProduceErrInfo(0, "string")
  280. }
  281. for i := 1; i < l; i++ {
  282. if ast.IsFloatArg(args[i]) || ast.IsTimeArg(args[i]) || ast.IsBooleanArg(args[i]) || ast.IsStringArg(args[i]) {
  283. return ProduceErrInfo(i, "int")
  284. }
  285. }
  286. if s, ok := args[1].(*ast.IntegerLiteral); ok {
  287. sv := s.Val
  288. if sv < 0 {
  289. return fmt.Errorf("The start index should not be a nagtive integer.")
  290. }
  291. if l == 3 {
  292. if e, ok1 := args[2].(*ast.IntegerLiteral); ok1 {
  293. ev := e.Val
  294. if ev < sv {
  295. return fmt.Errorf("The end index should be larger than start index.")
  296. }
  297. }
  298. }
  299. }
  300. return nil
  301. },
  302. }
  303. builtins["startswith"] = builtinFunc{
  304. fType: FuncTypeScalar,
  305. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  306. if args[0] == nil {
  307. return false, true
  308. }
  309. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  310. return strings.HasPrefix(arg0, arg1), true
  311. },
  312. val: ValidateTwoStrArg,
  313. }
  314. builtins["split_value"] = builtinFunc{
  315. fType: FuncTypeScalar,
  316. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  317. if args[0] == nil || args[1] == nil {
  318. return nil, true
  319. }
  320. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  321. ss := strings.Split(arg0, arg1)
  322. v, _ := cast.ToInt(args[2], cast.STRICT)
  323. if v > (len(ss) - 1) {
  324. return fmt.Errorf("%d out of index array (size = %d)", v, len(ss)), false
  325. } else {
  326. return ss[v], true
  327. }
  328. },
  329. val: func(_ api.FunctionContext, args []ast.Expr) error {
  330. l := len(args)
  331. if l != 3 {
  332. return fmt.Errorf("the arguments for split_value should be 3")
  333. }
  334. if ast.IsNumericArg(args[0]) || ast.IsTimeArg(args[0]) || ast.IsBooleanArg(args[0]) {
  335. return ProduceErrInfo(0, "string")
  336. }
  337. if ast.IsNumericArg(args[1]) || ast.IsTimeArg(args[1]) || ast.IsBooleanArg(args[1]) {
  338. return ProduceErrInfo(1, "string")
  339. }
  340. if ast.IsFloatArg(args[2]) || ast.IsTimeArg(args[2]) || ast.IsBooleanArg(args[2]) || ast.IsStringArg(args[2]) {
  341. return ProduceErrInfo(2, "int")
  342. }
  343. if s, ok := args[2].(*ast.IntegerLiteral); ok {
  344. if s.Val < 0 {
  345. return fmt.Errorf("The index should not be a nagtive integer.")
  346. }
  347. }
  348. return nil
  349. },
  350. }
  351. builtins["trim"] = builtinFunc{
  352. fType: FuncTypeScalar,
  353. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  354. if args[0] == nil {
  355. return nil, true
  356. }
  357. arg0 := cast.ToStringAlways(args[0])
  358. return strings.TrimSpace(arg0), true
  359. },
  360. val: ValidateOneStrArg,
  361. }
  362. builtins["upper"] = builtinFunc{
  363. fType: FuncTypeScalar,
  364. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  365. if args[0] == nil {
  366. return nil, true
  367. }
  368. arg0 := cast.ToStringAlways(args[0])
  369. return strings.ToUpper(arg0), true
  370. },
  371. val: ValidateOneStrArg,
  372. }
  373. }