parser.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package timefmt
  2. import (
  3. "git.swzry.com/zry/YAGTF/yagtf/tfelem"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. const parserTokenBufferSize = 128
  10. const regexpTimezoneTag = "^Timezone:([+-][0-9]{4})([A-Z]{3})$"
  11. type TimeElementFactoryFunc func() TimeElement
  12. type TimeElementExFactoryFunc func() TimeElementEx
  13. type NonDisplayTagFunc func(tp *FormatPrinterParsingAbstract)
  14. type FormatPrinterParsingAbstract struct {
  15. isEx bool
  16. tp *TimePrinter
  17. tpe *TimePrinterEx
  18. }
  19. func (this *FormatPrinterParsingAbstract) IsEx() bool {
  20. return this.isEx
  21. }
  22. func (this *FormatPrinterParsingAbstract) AddPureText(txt string) {
  23. if this.isEx {
  24. this.tpe.AddPureText(txt)
  25. } else {
  26. this.tp.AddPureText(txt)
  27. }
  28. }
  29. func (this *FormatPrinterParsingAbstract) AddExDataTag(e TimeElementEx) {
  30. this.tpe.AddTimeElementEx(e)
  31. }
  32. func (this *FormatPrinterParsingAbstract) AddElement(e TimeElement) {
  33. if this.isEx {
  34. this.tpe.AddTimeElement(e)
  35. } else {
  36. this.tp.AddElement(e)
  37. }
  38. }
  39. func (this *FormatPrinterParsingAbstract) UseTimezone(tz *time.Location) {
  40. if this.isEx {
  41. this.tpe.UseTimezone(tz)
  42. } else {
  43. this.tp.UseTimezone(tz)
  44. }
  45. }
  46. func (this *FormatPrinterParsingAbstract) UseUTC() {
  47. if this.isEx {
  48. this.tpe.UseUTC()
  49. } else {
  50. this.tp.UseUTC()
  51. }
  52. }
  53. func (this *FormatPrinterParsingAbstract) UseLocalTimezone() {
  54. if this.isEx {
  55. this.tpe.UseLocalTimezone()
  56. } else {
  57. this.tp.UseLocalTimezone()
  58. }
  59. }
  60. func (this *FormatPrinterParsingAbstract) GetTP() *TimePrinter {
  61. return this.tp
  62. }
  63. func (this *FormatPrinterParsingAbstract) GetTPE() *TimePrinterEx {
  64. return this.tpe
  65. }
  66. type FormatParser struct {
  67. tagList map[string]TimeElementFactoryFunc
  68. ndTagList map[string]NonDisplayTagFunc
  69. exTagList map[string]TimeElementExFactoryFunc
  70. tzsReg *regexp.Regexp
  71. isEx bool
  72. }
  73. func NewFormatParser(isEx bool) *FormatParser {
  74. f := &FormatParser{
  75. tagList: make(map[string]TimeElementFactoryFunc),
  76. ndTagList: make(map[string]NonDisplayTagFunc),
  77. exTagList: make(map[string]TimeElementExFactoryFunc),
  78. isEx: isEx,
  79. }
  80. f.addDefaultElementClasses()
  81. f.tzsReg, _ = regexp.Compile(regexpTimezoneTag)
  82. return f
  83. }
  84. func (this *FormatParser) AddElementClass(tagname string, ff TimeElementFactoryFunc) {
  85. this.tagList[tagname] = ff
  86. }
  87. func (this *FormatParser) AddTagAlias(alias string, tagname string) {
  88. v, ok := this.tagList[tagname]
  89. if ok {
  90. this.tagList[alias] = v
  91. }
  92. }
  93. func (this *FormatParser) AddNonDisplayTag(tagname string, nf NonDisplayTagFunc) {
  94. this.ndTagList[tagname] = nf
  95. }
  96. func (this *FormatParser) AddExDataTag(tagname string, ff TimeElementExFactoryFunc) {
  97. this.exTagList[tagname] = ff
  98. }
  99. func (this *FormatParser) ParseFormatString(tp *FormatPrinterParsingAbstract, fs string) {
  100. if len(fs) < 1 {
  101. return
  102. }
  103. if fs[0] == '!' {
  104. this.parseAdvancedFmt(tp, fs[1:])
  105. } else {
  106. this.parseBasicFmt(tp, fs)
  107. }
  108. }
  109. func (this *FormatParser) parseBasicFmt(tp *FormatPrinterParsingAbstract, fs string) {
  110. s := fs
  111. s = strings.Replace(s, "!", "<#000>", -1)
  112. s = strings.Replace(s, "yyyy", "<#001>", -1)
  113. s = strings.Replace(s, "yy", "<#002>", -1)
  114. s = strings.Replace(s, "MM", "<#003>", -1)
  115. s = strings.Replace(s, "M3", "<#004>", -1)
  116. s = strings.Replace(s, "M09", "<#005>", -1)
  117. s = strings.Replace(s, "M9", "<#006>", -1)
  118. s = strings.Replace(s, "M", "<#007>", -1)
  119. s = strings.Replace(s, "dd", "<#008>", -1)
  120. s = strings.Replace(s, "d", "<#009>", -1)
  121. s = strings.Replace(s, "HH", "<#010>", -1)
  122. s = strings.Replace(s, "hh", "<#011>", -1)
  123. s = strings.Replace(s, "H", "<#012>", -1)
  124. s = strings.Replace(s, "h", "<#013>", -1)
  125. s = strings.Replace(s, "mm", "<#014>", -1)
  126. s = strings.Replace(s, "ss", "<#015>", -1)
  127. s = strings.Replace(s, "E09", "<#016>", -1)
  128. s = strings.Replace(s, "E9", "<#017>", -1)
  129. s = strings.Replace(s, "E3", "<#018>", -1)
  130. s = strings.Replace(s, "A", "<#019>", -1)
  131. s = strings.Replace(s, "S1", "<#020>", -1)
  132. s = strings.Replace(s, "S2", "<#021>", -1)
  133. s = strings.Replace(s, "S3", "<#022>", -1)
  134. s = strings.Replace(s, "Z", "<#023>", -1)
  135. s = strings.Replace(s, "z", "<#024>", -1)
  136. this.parseAdvancedFmt(tp, s)
  137. }
  138. func (this *FormatParser) parseAdvancedFmt(tp *FormatPrinterParsingAbstract, fs string) {
  139. if len(fs) > 1 {
  140. if fs[0] == '!' {
  141. this.parseBasicFmt(tp, fs[1:])
  142. return
  143. }
  144. }
  145. stat := false
  146. ba := []byte(fs)
  147. ptbuf := make([]byte, 0, parserTokenBufferSize)
  148. for _, v := range ba {
  149. if stat {
  150. if v == '>' {
  151. this.processTag(tp, string(ptbuf))
  152. ptbuf = make([]byte, 0, parserTokenBufferSize)
  153. stat = false
  154. } else {
  155. ptbuf = append(ptbuf, v)
  156. }
  157. } else {
  158. if v == '<' {
  159. tp.AddPureText(string(ptbuf))
  160. ptbuf = make([]byte, 0, parserTokenBufferSize)
  161. stat = true
  162. } else {
  163. ptbuf = append(ptbuf, v)
  164. }
  165. }
  166. }
  167. }
  168. func (this *FormatParser) processTimezoneTag(tp *FormatPrinterParsingAbstract, tzs string, tzname string) {
  169. sg := 0
  170. if tzs[0] == '+' {
  171. sg = 1
  172. } else if tzs[0] == '-' {
  173. sg = -1
  174. } else {
  175. return
  176. }
  177. if len(tzs) != 5 {
  178. return
  179. }
  180. hs := tzs[1:3]
  181. ms := tzs[3:5]
  182. hi, err := strconv.Atoi(hs)
  183. if err != nil {
  184. return
  185. }
  186. mi, err := strconv.Atoi(ms)
  187. if err != nil {
  188. return
  189. }
  190. ofs := (hi*3600 + mi*60) * sg
  191. tz := time.FixedZone(tzname, ofs)
  192. tp.UseTimezone(tz)
  193. }
  194. func (this *FormatParser) processTag(tp *FormatPrinterParsingAbstract, tag string) {
  195. rrs := this.tzsReg.FindStringSubmatch(tag)
  196. if len(rrs) == 3 {
  197. this.processTimezoneTag(tp, rrs[1], rrs[2])
  198. return
  199. }
  200. if this.isEx {
  201. v0, ok := this.exTagList[tag]
  202. if ok {
  203. tp.AddExDataTag(v0())
  204. return
  205. }
  206. }
  207. v1, ok := this.ndTagList[tag]
  208. if ok {
  209. v1(tp)
  210. return
  211. }
  212. v2, ok := this.tagList[tag]
  213. if ok {
  214. tp.AddElement(v2())
  215. } else {
  216. tp.AddPureText("<" + tag + ">")
  217. }
  218. }
  219. func (this *FormatParser) addDefaultElementClasses() {
  220. this.AddNonDisplayTag("UTC", func(tp *FormatPrinterParsingAbstract) { tp.UseUTC() })
  221. this.AddNonDisplayTag("Local", func(tp *FormatPrinterParsingAbstract) { tp.UseLocalTimezone() })
  222. this.AddElementClass("year", func() TimeElement { return tfelem.NewYearElement(false) })
  223. this.AddElementClass("shortYear", func() TimeElement { return tfelem.NewYearElement(true) })
  224. this.AddElementClass("month", func() TimeElement { return tfelem.NewNumbericMonthElement(true) })
  225. this.AddElementClass("monthNoFill", func() TimeElement { return tfelem.NewNumbericMonthElement(false) })
  226. this.AddElementClass("monthAbbr", func() TimeElement { return tfelem.NewEnglishMonthElement(true, false) })
  227. this.AddElementClass("monthName", func() TimeElement { return tfelem.NewEnglishMonthElement(false, true) })
  228. this.AddElementClass("monthNameNoFill", func() TimeElement { return tfelem.NewEnglishMonthElement(false, false) })
  229. this.AddElementClass("day", func() TimeElement { return tfelem.NewDayElement(true) })
  230. this.AddElementClass("dayNoFill", func() TimeElement { return tfelem.NewDayElement(false) })
  231. this.AddElementClass("hour24", func() TimeElement { return tfelem.NewHour24hElement(true) })
  232. this.AddElementClass("hour24NoFill", func() TimeElement { return tfelem.NewHour24hElement(false) })
  233. this.AddElementClass("hour12", func() TimeElement { return tfelem.NewHour12hElement(true) })
  234. this.AddElementClass("hour12NoFill", func() TimeElement { return tfelem.NewHour12hElement(false) })
  235. this.AddElementClass("minute", func() TimeElement { return tfelem.NewMinuteElement() })
  236. this.AddElementClass("second", func() TimeElement { return tfelem.NewSecondElement() })
  237. this.AddElementClass("ms", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMilliSec() })
  238. this.AddElementClass("us", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMicroSec() })
  239. this.AddElementClass("ns", func() TimeElement { return tfelem.NewSecondFloatPartElementWithNanoSec() })
  240. this.AddElementClass("weekday", func() TimeElement { return tfelem.NewNumbericWeekDayElement() })
  241. this.AddElementClass("weekdayAbbr", func() TimeElement { return tfelem.NewEnglishWeekDayElement(true, false) })
  242. this.AddElementClass("weekdayName", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, true) })
  243. this.AddElementClass("weekdayNameNoFill", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, false) })
  244. this.AddElementClass("ampm", func() TimeElement { return tfelem.NewAMPMElement() })
  245. this.AddElementClass("yearweek", func() TimeElement { return tfelem.NewWeekElement(true) })
  246. this.AddElementClass("yearweekNoFill", func() TimeElement { return tfelem.NewWeekElement(false) })
  247. this.AddElementClass("yearday", func() TimeElement { return tfelem.NewYearDayElement(true) })
  248. this.AddElementClass("yeardayNoFill", func() TimeElement { return tfelem.NewYearDayElement(false) })
  249. this.AddElementClass("timezone", func() TimeElement { return tfelem.NewTimeZoneUTCOffsetElement() })
  250. this.AddElementClass("timezoneAbbr", func() TimeElement { return tfelem.NewTimeZoneAbbrElement() })
  251. this.AddElementClass("timezoneSec", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(true) })
  252. this.AddElementClass("timezoneSecNoFill", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(false) })
  253. this.AddElementClass("iso8601date", func() TimeElement { return tfelem.NewISO8601DateElement() })
  254. this.AddElementClass("iso8601time", func() TimeElement { return tfelem.NewISO8601TimeElement() })
  255. this.AddElementClass("iso8601full", func() TimeElement { return tfelem.NewISO8601FullElement() })
  256. this.AddElementClass("common", func() TimeElement { return tfelem.NewCommonDatetimeElement() })
  257. this.AddElementClass("nginx", func() TimeElement { return tfelem.NewNginxDefaultElement() })
  258. this.AddElementClass("!", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} })
  259. this.AddElementClass("lt", func() TimeElement { return &tfelem.PureTextElement{PureText: "<"} })
  260. this.AddElementClass("gt", func() TimeElement { return &tfelem.PureTextElement{PureText: ">"} })
  261. this.AddElementClass("q", func() TimeElement { return &tfelem.PureTextElement{PureText: `"`} })
  262. this.AddElementClass("sq", func() TimeElement { return &tfelem.PureTextElement{PureText: "'"} })
  263. this.AddElementClass("tab", func() TimeElement { return &tfelem.PureTextElement{PureText: "\t"} })
  264. this.AddElementClass("br", func() TimeElement { return &tfelem.PureTextElement{PureText: "\n"} })
  265. this.AddElementClass("cr", func() TimeElement { return &tfelem.PureTextElement{PureText: "\r"} })
  266. this.AddElementClass("sp", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} })
  267. this.AddTagAlias("y", "year")
  268. this.AddTagAlias("sy", "shortYear")
  269. this.AddTagAlias("mon", "month")
  270. this.AddTagAlias("monNF", "monthNoFill")
  271. this.AddTagAlias("monA", "monthAbbr")
  272. this.AddTagAlias("monN", "monthName")
  273. this.AddTagAlias("monNNF", "monthNameNoFill")
  274. this.AddTagAlias("d", "day")
  275. this.AddTagAlias("dNF", "dayNoFill")
  276. this.AddTagAlias("h24", "hour24")
  277. this.AddTagAlias("h12", "hour12")
  278. this.AddTagAlias("h24NF", "hour24NoFill")
  279. this.AddTagAlias("h12NF", "hour12NoFill")
  280. this.AddTagAlias("min", "minute")
  281. this.AddTagAlias("s", "second")
  282. this.AddTagAlias("wd", "weekday")
  283. this.AddTagAlias("wdN", "weekdayName")
  284. this.AddTagAlias("wdNNF", "weekdayNameNoFill")
  285. this.AddTagAlias("wdA", "weekdayAbbr")
  286. this.AddTagAlias("yw", "yearweek")
  287. this.AddTagAlias("ywNF", "yearweekNoFill")
  288. this.AddTagAlias("yd", "yearday")
  289. this.AddTagAlias("ydNF", "yeardayNoFill")
  290. this.AddTagAlias("tz", "timezone")
  291. this.AddTagAlias("tzA", "timezoneAbbr")
  292. this.AddTagAlias("tzS", "timezoneSec")
  293. this.AddTagAlias("tzSNF", "timezoneSecNoFill")
  294. this.AddTagAlias("i8d", "iso8601date")
  295. this.AddTagAlias("i8t", "iso8601time")
  296. this.AddTagAlias("i8f", "iso8601full")
  297. this.AddTagAlias("#000", "!")
  298. this.AddTagAlias("#001", "year")
  299. this.AddTagAlias("#002", "shortYear")
  300. this.AddTagAlias("#003", "month")
  301. this.AddTagAlias("#004", "monthAbbr")
  302. this.AddTagAlias("#005", "monthName")
  303. this.AddTagAlias("#006", "monthNameNoFill")
  304. this.AddTagAlias("#007", "monthNoFill")
  305. this.AddTagAlias("#008", "day")
  306. this.AddTagAlias("#009", "dayNoFill")
  307. this.AddTagAlias("#010", "hour24")
  308. this.AddTagAlias("#011", "hour12")
  309. this.AddTagAlias("#012", "hour24NoFill")
  310. this.AddTagAlias("#013", "hour12NoFill")
  311. this.AddTagAlias("#014", "minute")
  312. this.AddTagAlias("#015", "second")
  313. this.AddTagAlias("#016", "weekdayName")
  314. this.AddTagAlias("#017", "weekdayNameNoFill")
  315. this.AddTagAlias("#018", "weekdayAbbr")
  316. this.AddTagAlias("#019", "ampm")
  317. this.AddTagAlias("#020", "ms")
  318. this.AddTagAlias("#021", "us")
  319. this.AddTagAlias("#022", "ns")
  320. this.AddTagAlias("#023", "timezoneAbbr")
  321. this.AddTagAlias("#024", "timezone")
  322. }