stringlib.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. package lua
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/yuin/gopher-lua/pm"
  6. )
  7. const emptyLString LString = LString("")
  8. func OpenString(L *LState) int {
  9. var mod *LTable
  10. //_, ok := L.G.builtinMts[int(LTString)]
  11. //if !ok {
  12. mod = L.RegisterModule(StringLibName, strFuncs).(*LTable)
  13. gmatch := L.NewClosure(strGmatch, L.NewFunction(strGmatchIter))
  14. mod.RawSetString("gmatch", gmatch)
  15. mod.RawSetString("gfind", gmatch)
  16. mod.RawSetString("__index", mod)
  17. L.G.builtinMts[int(LTString)] = mod
  18. //}
  19. L.Push(mod)
  20. return 1
  21. }
  22. var strFuncs = map[string]LGFunction{
  23. "byte": strByte,
  24. "char": strChar,
  25. "dump": strDump,
  26. "find": strFind,
  27. "format": strFormat,
  28. "gsub": strGsub,
  29. "len": strLen,
  30. "lower": strLower,
  31. "match": strMatch,
  32. "rep": strRep,
  33. "reverse": strReverse,
  34. "sub": strSub,
  35. "upper": strUpper,
  36. }
  37. func strByte(L *LState) int {
  38. str := L.CheckString(1)
  39. start := L.OptInt(2, 1) - 1
  40. end := L.OptInt(3, -1)
  41. l := len(str)
  42. if start < 0 {
  43. start = l + start + 1
  44. }
  45. if end < 0 {
  46. end = l + end + 1
  47. }
  48. if L.GetTop() == 2 {
  49. if start < 0 || start >= l {
  50. return 0
  51. }
  52. L.Push(LNumber(str[start]))
  53. return 1
  54. }
  55. start = intMax(start, 0)
  56. end = intMin(end, l)
  57. if end < 0 || end <= start || start >= l {
  58. return 0
  59. }
  60. for i := start; i < end; i++ {
  61. L.Push(LNumber(str[i]))
  62. }
  63. return end - start
  64. }
  65. func strChar(L *LState) int {
  66. top := L.GetTop()
  67. bytes := make([]byte, L.GetTop())
  68. for i := 1; i <= top; i++ {
  69. bytes[i-1] = uint8(L.CheckInt(i))
  70. }
  71. L.Push(LString(string(bytes)))
  72. return 1
  73. }
  74. func strDump(L *LState) int {
  75. L.RaiseError("GopherLua does not support the string.dump")
  76. return 0
  77. }
  78. func strFind(L *LState) int {
  79. str := L.CheckString(1)
  80. pattern := L.CheckString(2)
  81. if len(pattern) == 0 {
  82. L.Push(LNumber(1))
  83. L.Push(LNumber(0))
  84. return 2
  85. }
  86. init := luaIndex2StringIndex(str, L.OptInt(3, 1), true)
  87. plain := false
  88. if L.GetTop() == 4 {
  89. plain = LVAsBool(L.Get(4))
  90. }
  91. if plain {
  92. pos := strings.Index(str[init:], pattern)
  93. if pos < 0 {
  94. L.Push(LNil)
  95. return 1
  96. }
  97. L.Push(LNumber(init+pos) + 1)
  98. L.Push(LNumber(init + pos + len(pattern)))
  99. return 2
  100. }
  101. mds, err := pm.Find(pattern, unsafeFastStringToReadOnlyBytes(str), init, 1)
  102. if err != nil {
  103. L.RaiseError(err.Error())
  104. }
  105. if len(mds) == 0 {
  106. L.Push(LNil)
  107. return 1
  108. }
  109. md := mds[0]
  110. L.Push(LNumber(md.Capture(0) + 1))
  111. L.Push(LNumber(md.Capture(1)))
  112. for i := 2; i < md.CaptureLength(); i += 2 {
  113. if md.IsPosCapture(i) {
  114. L.Push(LNumber(md.Capture(i)))
  115. } else {
  116. L.Push(LString(str[md.Capture(i):md.Capture(i+1)]))
  117. }
  118. }
  119. return md.CaptureLength()/2 + 1
  120. }
  121. func strFormat(L *LState) int {
  122. str := L.CheckString(1)
  123. args := make([]interface{}, L.GetTop()-1)
  124. top := L.GetTop()
  125. for i := 2; i <= top; i++ {
  126. args[i-2] = L.Get(i)
  127. }
  128. npat := strings.Count(str, "%") - strings.Count(str, "%%")
  129. L.Push(LString(fmt.Sprintf(str, args[:intMin(npat, len(args))]...)))
  130. return 1
  131. }
  132. func strGsub(L *LState) int {
  133. str := L.CheckString(1)
  134. pat := L.CheckString(2)
  135. L.CheckTypes(3, LTString, LTTable, LTFunction)
  136. repl := L.CheckAny(3)
  137. limit := L.OptInt(4, -1)
  138. mds, err := pm.Find(pat, unsafeFastStringToReadOnlyBytes(str), 0, limit)
  139. if err != nil {
  140. L.RaiseError(err.Error())
  141. }
  142. if len(mds) == 0 {
  143. L.SetTop(1)
  144. L.Push(LNumber(0))
  145. return 2
  146. }
  147. switch lv := repl.(type) {
  148. case LString:
  149. L.Push(LString(strGsubStr(L, str, string(lv), mds)))
  150. case *LTable:
  151. L.Push(LString(strGsubTable(L, str, lv, mds)))
  152. case *LFunction:
  153. L.Push(LString(strGsubFunc(L, str, lv, mds)))
  154. }
  155. L.Push(LNumber(len(mds)))
  156. return 2
  157. }
  158. type replaceInfo struct {
  159. Indicies []int
  160. String string
  161. }
  162. func checkCaptureIndex(L *LState, m *pm.MatchData, idx int) {
  163. if idx <= 2 {
  164. return
  165. }
  166. if idx >= m.CaptureLength() {
  167. L.RaiseError("invalid capture index")
  168. }
  169. }
  170. func capturedString(L *LState, m *pm.MatchData, str string, idx int) string {
  171. checkCaptureIndex(L, m, idx)
  172. if idx >= m.CaptureLength() && idx == 2 {
  173. idx = 0
  174. }
  175. if m.IsPosCapture(idx) {
  176. return fmt.Sprint(m.Capture(idx))
  177. } else {
  178. return str[m.Capture(idx):m.Capture(idx+1)]
  179. }
  180. }
  181. func strGsubDoReplace(str string, info []replaceInfo) string {
  182. offset := 0
  183. buf := []byte(str)
  184. for _, replace := range info {
  185. oldlen := len(buf)
  186. b1 := append([]byte(""), buf[0:offset+replace.Indicies[0]]...)
  187. b2 := []byte("")
  188. index2 := offset + replace.Indicies[1]
  189. if index2 <= len(buf) {
  190. b2 = append(b2, buf[index2:len(buf)]...)
  191. }
  192. buf = append(b1, replace.String...)
  193. buf = append(buf, b2...)
  194. offset += len(buf) - oldlen
  195. }
  196. return string(buf)
  197. }
  198. func strGsubStr(L *LState, str string, repl string, matches []*pm.MatchData) string {
  199. infoList := make([]replaceInfo, 0, len(matches))
  200. for _, match := range matches {
  201. start, end := match.Capture(0), match.Capture(1)
  202. sc := newFlagScanner('%', "", "", repl)
  203. for c, eos := sc.Next(); !eos; c, eos = sc.Next() {
  204. if !sc.ChangeFlag {
  205. if sc.HasFlag {
  206. if c >= '0' && c <= '9' {
  207. sc.AppendString(capturedString(L, match, str, 2*(int(c)-48)))
  208. } else {
  209. sc.AppendChar('%')
  210. sc.AppendChar(c)
  211. }
  212. sc.HasFlag = false
  213. } else {
  214. sc.AppendChar(c)
  215. }
  216. }
  217. }
  218. infoList = append(infoList, replaceInfo{[]int{start, end}, sc.String()})
  219. }
  220. return strGsubDoReplace(str, infoList)
  221. }
  222. func strGsubTable(L *LState, str string, repl *LTable, matches []*pm.MatchData) string {
  223. infoList := make([]replaceInfo, 0, len(matches))
  224. for _, match := range matches {
  225. idx := 0
  226. if match.CaptureLength() > 2 { // has captures
  227. idx = 2
  228. }
  229. var value LValue
  230. if match.IsPosCapture(idx) {
  231. value = L.GetTable(repl, LNumber(match.Capture(idx)))
  232. } else {
  233. value = L.GetField(repl, str[match.Capture(idx):match.Capture(idx+1)])
  234. }
  235. if !LVIsFalse(value) {
  236. infoList = append(infoList, replaceInfo{[]int{match.Capture(0), match.Capture(1)}, LVAsString(value)})
  237. }
  238. }
  239. return strGsubDoReplace(str, infoList)
  240. }
  241. func strGsubFunc(L *LState, str string, repl *LFunction, matches []*pm.MatchData) string {
  242. infoList := make([]replaceInfo, 0, len(matches))
  243. for _, match := range matches {
  244. start, end := match.Capture(0), match.Capture(1)
  245. L.Push(repl)
  246. nargs := 0
  247. if match.CaptureLength() > 2 { // has captures
  248. for i := 2; i < match.CaptureLength(); i += 2 {
  249. if match.IsPosCapture(i) {
  250. L.Push(LNumber(match.Capture(i)))
  251. } else {
  252. L.Push(LString(capturedString(L, match, str, i)))
  253. }
  254. nargs++
  255. }
  256. } else {
  257. L.Push(LString(capturedString(L, match, str, 0)))
  258. nargs++
  259. }
  260. L.Call(nargs, 1)
  261. ret := L.reg.Pop()
  262. if !LVIsFalse(ret) {
  263. infoList = append(infoList, replaceInfo{[]int{start, end}, LVAsString(ret)})
  264. }
  265. }
  266. return strGsubDoReplace(str, infoList)
  267. }
  268. type strMatchData struct {
  269. str string
  270. pos int
  271. matches []*pm.MatchData
  272. }
  273. func strGmatchIter(L *LState) int {
  274. md := L.CheckUserData(1).Value.(*strMatchData)
  275. str := md.str
  276. matches := md.matches
  277. idx := md.pos
  278. md.pos += 1
  279. if idx == len(matches) {
  280. return 0
  281. }
  282. L.Push(L.Get(1))
  283. match := matches[idx]
  284. if match.CaptureLength() == 2 {
  285. L.Push(LString(str[match.Capture(0):match.Capture(1)]))
  286. return 1
  287. }
  288. for i := 2; i < match.CaptureLength(); i += 2 {
  289. if match.IsPosCapture(i) {
  290. L.Push(LNumber(match.Capture(i)))
  291. } else {
  292. L.Push(LString(str[match.Capture(i):match.Capture(i+1)]))
  293. }
  294. }
  295. return match.CaptureLength()/2 - 1
  296. }
  297. func strGmatch(L *LState) int {
  298. str := L.CheckString(1)
  299. pattern := L.CheckString(2)
  300. mds, err := pm.Find(pattern, []byte(str), 0, -1)
  301. if err != nil {
  302. L.RaiseError(err.Error())
  303. }
  304. L.Push(L.Get(UpvalueIndex(1)))
  305. ud := L.NewUserData()
  306. ud.Value = &strMatchData{str, 0, mds}
  307. L.Push(ud)
  308. return 2
  309. }
  310. func strLen(L *LState) int {
  311. str := L.CheckString(1)
  312. L.Push(LNumber(len(str)))
  313. return 1
  314. }
  315. func strLower(L *LState) int {
  316. str := L.CheckString(1)
  317. L.Push(LString(strings.ToLower(str)))
  318. return 1
  319. }
  320. func strMatch(L *LState) int {
  321. str := L.CheckString(1)
  322. pattern := L.CheckString(2)
  323. offset := L.OptInt(3, 1)
  324. l := len(str)
  325. if offset < 0 {
  326. offset = l + offset + 1
  327. }
  328. offset--
  329. if offset < 0 {
  330. offset = 0
  331. }
  332. mds, err := pm.Find(pattern, unsafeFastStringToReadOnlyBytes(str), offset, 1)
  333. if err != nil {
  334. L.RaiseError(err.Error())
  335. }
  336. if len(mds) == 0 {
  337. L.Push(LNil)
  338. return 0
  339. }
  340. md := mds[0]
  341. nsubs := md.CaptureLength() / 2
  342. switch nsubs {
  343. case 1:
  344. L.Push(LString(str[md.Capture(0):md.Capture(1)]))
  345. return 1
  346. default:
  347. for i := 2; i < md.CaptureLength(); i += 2 {
  348. if md.IsPosCapture(i) {
  349. L.Push(LNumber(md.Capture(i)))
  350. } else {
  351. L.Push(LString(str[md.Capture(i):md.Capture(i+1)]))
  352. }
  353. }
  354. return nsubs - 1
  355. }
  356. }
  357. func strRep(L *LState) int {
  358. str := L.CheckString(1)
  359. n := L.CheckInt(2)
  360. if n < 0 {
  361. L.Push(emptyLString)
  362. } else {
  363. L.Push(LString(strings.Repeat(str, n)))
  364. }
  365. return 1
  366. }
  367. func strReverse(L *LState) int {
  368. str := L.CheckString(1)
  369. bts := []byte(str)
  370. out := make([]byte, len(bts))
  371. for i, j := 0, len(bts)-1; j >= 0; i, j = i+1, j-1 {
  372. out[i] = bts[j]
  373. }
  374. L.Push(LString(string(out)))
  375. return 1
  376. }
  377. func strSub(L *LState) int {
  378. str := L.CheckString(1)
  379. start := luaIndex2StringIndex(str, L.CheckInt(2), true)
  380. end := luaIndex2StringIndex(str, L.OptInt(3, -1), false)
  381. l := len(str)
  382. if start >= l || end < start {
  383. L.Push(emptyLString)
  384. } else {
  385. L.Push(LString(str[start:end]))
  386. }
  387. return 1
  388. }
  389. func strUpper(L *LState) int {
  390. str := L.CheckString(1)
  391. L.Push(LString(strings.ToUpper(str)))
  392. return 1
  393. }
  394. func luaIndex2StringIndex(str string, i int, start bool) int {
  395. if start && i != 0 {
  396. i -= 1
  397. }
  398. l := len(str)
  399. if i < 0 {
  400. i = l + i + 1
  401. }
  402. i = intMax(0, i)
  403. if !start && i > l {
  404. i = l
  405. }
  406. return i
  407. }
  408. //