winnerorder.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. package pretreated
  2. import (
  3. "jy/clear"
  4. //"jy/clear"
  5. "jy/util"
  6. qutil "qfw/util"
  7. "regexp"
  8. "strconv"
  9. "strings"
  10. "unicode/utf8"
  11. )
  12. type WinnerOrderEntity struct {
  13. }
  14. type WinnerFlag struct {
  15. index int //数组索引
  16. start int //数组开始索引
  17. end int //数组结束索引
  18. textStart int //文本开始索引
  19. textEnd int //文本结束索引
  20. max int
  21. indexs []int
  22. }
  23. var (
  24. winnerOrderEntity = &WinnerOrderEntity{}
  25. numberReg = regexp.MustCompile("[一二三四五六七八九十0-9]+")
  26. numberReg2 = regexp.MustCompile("[\\d一二三四五六七八九十.,,]+")
  27. thisNumberReg = regexp.MustCompile("第" + numberReg.String())
  28. winnerReg0 = regexp.MustCompile("(中标候选人第\\d名|第[0-9一二三四五](中选|中标|成交)候选人|[第|弟][0-9一二三四五]中标人|中标人[1-9])")
  29. winnerReg1 = regexp.MustCompile("(^|[^为])(【?(推荐)?第[一二三四五六七八九十1-9]+(合格|名|包|标段)?】?([候|侯]选)?(入围|备选|成交|中[标|选])人?([((]成交[))])?([候|侯]选|排序)?(人(单位)?|供[应货]商|单位|机构)(名称)?为?)($|[^,;;。,])")
  30. winnerReg2 = regexp.MustCompile("(排名第[一二三四五六七八九十1-9]+|[第|弟][一二三四五六七八九十1-9]+(中标|中选)?[候|侯]选人|中标候选人排名[:]\\d)")
  31. //winnerReg2 = regexp.MustCompile("(第[一二三四五六七八九十1-9]+(候|侯)选人)")
  32. winnerReg3 = regexp.MustCompile("((中标候选人)?第[一二三四五六七八九十1-9]+名)|()")
  33. winnerReg4 = regexp.MustCompile("((确认|推荐|评审|排[名|序])[为::]+|(由高到低排序前.名|公示下列内容|(确定|推荐)的?中[标|选]候选人|\n中[标|选]候选.{1,3}\\s*\n|\n(中[标|选]候选.{1,3}[::\u3000\u2003\u00a0\\s]|成交候选供应商)|(排[名|序]|公[示|告]|具体|推荐|结果(公示)?|中[标|选]候选人.{0,2})如下|[一二三四五六七八九十\\d]+、(中[标|选]候选[^\n::]{1,8}|.{0,8}(成交|结果)信息|成交[^\n::]{2,8}))[为::]?)")
  34. winnerReg5 = regexp.MustCompile("([^,;;。,、\n投标人]+?)(为?)(第[一二三四五六七八九十1-9]+(成交|中标)?([候|侯]选(人|供应商|单位|机构)|名)|排名第[一二三四五六七八九十1-9]+)([,;;。,、]|\\s+\n)")
  35. winnerReg6 = regexp.MustCompile("(^(排名)?第[一二三四五六七八九十1-9]+[名中标成交备选候人单位供应商]*)")
  36. winnerReg7 = regexp.MustCompile("第[一二三四五六七八九十]{1}标段[::]")
  37. winnerReg8 = regexp.MustCompile("(第[一二三四五六七八九十]中选候选人)[::\\s]+?[((]1[))][\\s]+?(单位名称)[::]?(.*)[\\s]+?[((]2[))][\\s]+(参选报价|投标报价(含税))[::]?(.*)")
  38. //winnerReg8 = regexp.MustCompile("(第[一二三四五六七八九十]中标候选人)[::]?\n(1)单位名称:(.*)\n(2)投标报价(含税):(.*)")
  39. winnerReg9 = regexp.MustCompile("(第[一二三四五六七八九十]中[选|标]?候选人|中标人[1-9])[::\\s]+?([\u4E00-\u9FA5]{4,20})[\\s]+([0-9\\.\\s万元]+)")
  40. winnerReg10 = regexp.MustCompile("(第[一二三四五六七八九十]中标人)[::\\s]+?报价[¥]?([0-9\\.\\s万元]+)[;;]([\u4E00-\u9FA5]{4,20})")
  41. winnerReg11 = regexp.MustCompile("([弟|第][一二三四五六七八九十]中[标|选]候选人)[::\\s]+?(单位名称|投标人名称)[::]?(.*)[\\s]+?(参选报价|投标报价[((]含税[))]|投标报价[((]元[))])[::]?(.*)")
  42. winnerReg12 = regexp.MustCompile("(中[标|选]候选人[弟|第][一二三四五六七八九十0-9]名)[::\\s]+?(.*)[\\s,,]+?(投标报价)[::]?([0-9\\.\\s万元]+)")
  43. winnerReg13 = regexp.MustCompile("([弟|第][一二三四五六七八九十0-9])\n(成交候选人|成交供应商)\n(.*)\n([0-9\\.\\s万元]+)")
  44. winnerRegclear = regexp.MustCompile("(买方人员|经评审.*排名第[一二三四五六七八九十1-9]+)")
  45. colonEndReg = regexp.MustCompile("[::]$")
  46. toWarpReg = regexp.MustCompile("[,。,;;]+")
  47. findamountReg = regexp.MustCompile("[,。,;;\u3000\u2003\u00a0\\s]+")
  48. amountReg = regexp.MustCompile("^\\d+(\\.\\d+)?([百|千]?元|[百|千]?[万|亿]元?)$")
  49. companyWarpReg = regexp.MustCompile("(公司)(.+?[::])")
  50. findCompanyReg = regexp.MustCompile("[^::]+公司")
  51. colonSpaceReg = regexp.MustCompile("[::]\\s+")
  52. findCandidate = regexp.MustCompile("(^.{5,}(公司|集团|单位|机构|企业|厂|场|院|所|店|中心|市|局|站|城|处|行|部|队|联合[会|体])|工作室)")
  53. findCandidate2 = regexp.MustCompile("(^.{5,}(公司|集团|单位|机构|企业|厂|场|院|所|店|中心|局|站|城|处|行|部|队|联合[会|体]|工作室|有限司)$)")
  54. clearSpace1 = regexp.MustCompile("([((][\\d一二三四五六七八九十][))][\\s\u3000\u2003\u00a0\\t]*|<[^>].+?>)")
  55. clearSpace2 = regexp.MustCompile("</?[^>]+>")
  56. offerReg = regexp.MustCompile("(中标|磋商|投标|报|单|成交)总?(价|金额)")
  57. )
  58. /*
  59. *查找分包中的中标人排序
  60. *text文本,flag非否精确查找
  61. *from 来源
  62. */
  63. func (wo *WinnerOrderEntity) Find(text string, flag bool, from int, isSite bool, codeSite string) []map[string]interface{} {
  64. if clearSpace2.MatchString(text){
  65. text = TextAfterRemoveTable(text)
  66. }//评得分估|标的|班子成员|人员
  67. text = winnerRegclear.ReplaceAllString(text,"")
  68. if nswinnertabletag.MatchString(text) {
  69. return []map[string]interface{}{}
  70. }
  71. text = winnerReg5.ReplaceAllString(text, "\n$3:$1\n")
  72. text = winnerReg8.ReplaceAllString(text,"\n${1}:${3}\n中标金额:${5}\n")
  73. text = winnerReg9.ReplaceAllString(text,"\n${1}:${2}\n中标金额:${3}\n")
  74. text = winnerReg10.ReplaceAllString(text,"\n${1}:${3}\n中标金额:${2}\n")
  75. text = winnerReg11.ReplaceAllString(text,"\n${1}:${3}\n中标金额:${5}\n")
  76. text = winnerReg12.ReplaceAllString(text,"\n${1}:${2}\n中标金额:${4}\n")
  77. text = winnerReg13.ReplaceAllString(text,"\n${1}${2}:${3}\n中标金额:${4}\n")
  78. /*
  79. 第一候选人:河南冠嘉建设工程有限公司41.9450万元 合格  90日历天  孔祥子
  80. 中标人名称 中标价格 中标份额(%)
  81. 中标人1 山东益通安装有限公司 0.97元 55%
  82. 中标人2 山东鸿华建筑安装工程有限公司 0.96元 45%
  83. */
  84. text = clearSpace1.ReplaceAllString(text, "") //清理(1) 单位名称:成都维诺信科技有限公司-->单位名称:成都维诺信科技有限公司
  85. if strings.TrimSpace(text) == "" {
  86. return []map[string]interface{}{}
  87. }
  88. blocks := winnerReg4.Split(text, -1)
  89. if len(blocks) == 0 {
  90. blocks = append(blocks, text)
  91. } else if len(blocks) == 1 {
  92. blocks = winnerReg7.Split(text, -1)
  93. }
  94. winners := wo.findByReg(text, blocks, winnerReg0, from, isSite, codeSite)
  95. if len(winners) == 0 {
  96. winners = wo.findByReg(text, blocks, winnerReg2, from, isSite, codeSite)
  97. }
  98. if len(winners) == 0 {
  99. if flag {
  100. //异常
  101. winners = wo.findByReg(text, blocks, winnerReg3, from, isSite, codeSite)
  102. } else {
  103. indexs_4 := winnerReg4.Split(text, -1)
  104. if len(indexs_4) > 1 {
  105. for _, v_4 := range indexs_4 {
  106. indexs_3 := winnerReg3.FindAllStringIndex(v_4, -1)
  107. if len(indexs_3) < 2 {
  108. continue
  109. }
  110. for _, v_3 := range indexs_3 {
  111. if strings.Count(v_4[:v_3[1]], "\n") <= 3 {
  112. winners = wo.findByReg(text, blocks, winnerReg3, from, isSite, codeSite)
  113. break
  114. }
  115. }
  116. }
  117. }
  118. }
  119. }
  120. //候选人有一半以上是错误的话,那么就认为全部抽错了
  121. invalidCount := 0
  122. for _, v := range winners {
  123. if !findCandidate.MatchString(qutil.ObjToString(v["entname"])) {
  124. invalidCount++
  125. }
  126. }
  127. if invalidCount > len(winners)/2 {
  128. return []map[string]interface{}{}
  129. }
  130. return winners
  131. }
  132. //获取中标人排序文本
  133. func (wo *WinnerOrderEntity) getText(text string, blocks []string, reg_2 *regexp.Regexp, from int) []string {
  134. isWinnerReg1 := reg_2 == winnerReg1
  135. rdata := []string{}
  136. //确定中标候选人排序在哪个块里面
  137. rightIndex, prevMax := -1, -1
  138. rightIndexs := []int{}
  139. var winnerFlag []*WinnerFlag
  140. for b_k, b_v := range blocks {
  141. indexs := []*WinnerFlag{}
  142. array := reg_2.FindAllStringSubmatchIndex(b_v, -1)
  143. for _, v := range array {
  144. var wrfg *WinnerFlag
  145. if isWinnerReg1 {
  146. if v[4]<0 || v[5]<0 {
  147. continue
  148. }
  149. wrfg = &WinnerFlag{
  150. index: wo.toNumber(b_v[v[4]:v[5]], 0),
  151. textStart: v[4],
  152. textEnd: v[5],
  153. }
  154. } else {
  155. if v[2]<0 || v[3]<0 {
  156. continue
  157. }
  158. wrfg = &WinnerFlag{
  159. index: wo.toNumber(b_v[v[2]:v[3]], 0),
  160. textStart: v[2],
  161. textEnd: v[3],
  162. }
  163. }
  164. indexs = append(indexs, wrfg)
  165. }
  166. wf := wo.getMax(indexs, from)
  167. if wf != nil && wf.max >= prevMax {
  168. prevMax = wf.max
  169. rightIndex = b_k
  170. rightIndexs = append(rightIndexs, b_k)
  171. winnerFlag = append(winnerFlag, wf)
  172. }
  173. }
  174. ////在这个块里面,截取
  175. if rightIndex == -1 {
  176. return rdata
  177. }
  178. for i, rightIndex := range rightIndexs {
  179. text = blocks[rightIndex]
  180. warpCount := wo.interceptText(winnerFlag[i].indexs, text)
  181. if warpCount == 0 {
  182. warpCount = 1
  183. }
  184. textEnd := text[winnerFlag[i].textEnd:]
  185. text = text[winnerFlag[i].textStart:winnerFlag[i].textEnd]
  186. warpIndex := regSpliteSegment.FindAllStringIndex(textEnd, -1)
  187. if len(warpIndex) >= warpCount {
  188. textEnd = textEnd[:warpIndex[warpCount-1][1]]
  189. }
  190. text = text + textEnd
  191. if isWinnerReg1 {
  192. text = reg_2.ReplaceAllString(text, "$1\n$2$15")
  193. } else {
  194. text = reg_2.ReplaceAllString(text, "\n$1")
  195. }
  196. text = regReplWrapSpace.ReplaceAllString(text, "")
  197. lines := SspacekvEntity.getLines(text)
  198. text = ""
  199. for k, v := range lines {
  200. v = strings.TrimSpace(v)
  201. v = colonSpaceReg.ReplaceAllString(v, ":")
  202. if reg_2.MatchString(v) && !regDivision.MatchString(v) {
  203. if isWinnerReg1 {
  204. v = reg_2.ReplaceAllString(v, "$1$2:$15")
  205. } else {
  206. v = reg_2.ReplaceAllString(v, "$1:")
  207. }
  208. }
  209. //逗号之类符号的分割,查找紧跟在中标候选人之后的中标金额
  210. //如果后面没有什么标识,只有金额的情况下,把中标金额加到金额前面
  211. if reg_2.MatchString(v) {
  212. //两个kv连到一起
  213. if len(regDivision.FindAllString(v, -1)) > 1 && !findamountReg.MatchString(v) {
  214. v = companyWarpReg.ReplaceAllString(v, "$1\n$2")
  215. }
  216. vs := findamountReg.Split(v, -1)
  217. if len(vs) > 1 {
  218. vs_1 := strings.TrimSpace(vs[1])
  219. if amountReg.MatchString(vs_1) {
  220. v = strings.Replace(v, vs[1], "中标金额:"+vs_1, 1)
  221. }
  222. }
  223. }
  224. v = toWarpReg.ReplaceAllString(v, "\n")
  225. text += v
  226. if (!reg_2.MatchString(v) || !colonEndReg.MatchString(v)) && k < len(lines)-1 {
  227. text += "\n"
  228. }
  229. }
  230. rdata = append(rdata, text)
  231. }
  232. return rdata
  233. }
  234. //抽取对应的排序结果
  235. func (wo *WinnerOrderEntity) findByReg(content string, blocks []string, reg_2 *regexp.Regexp, from int, isSite bool, codeSite string) []map[string]interface{} {
  236. text := wo.getText(content, blocks, reg_2, from)
  237. winners := []map[string]interface{}{}
  238. if len(text) < 1 {
  239. return winners
  240. }
  241. for i, v := range text {
  242. object := map[string]interface{}{}
  243. count := 0
  244. kvs := colonkvEntity.getColonSpaceKV(v, isSite, codeSite)
  245. for _, kv := range kvs {
  246. k, v := kv.Key, kv.Value
  247. if regDivision.MatchString(v) {
  248. v_k := regDivision.Split(v, -1)[0]
  249. if reg_2.MatchString(v_k) {
  250. k = v_k
  251. }
  252. }
  253. if reg_2.MatchString(k) { //中标人
  254. if len(object) > 0 {
  255. winners = append(winners, object)
  256. object = map[string]interface{}{}
  257. }
  258. val := wo.clear("中标单位", v)
  259. if val != nil && utf8.RuneCountInString(qutil.ObjToString(val)) > 5 {
  260. count++
  261. object["entname"] = strings.TrimRight(strings.ReplaceAll(strings.TrimSpace(qutil.ObjToString(val)), "公司", "公司,"), ",")
  262. object["sort"] = wo.toNumber(k, count)
  263. object["sortstr"] = thisNumberReg.FindString(k)
  264. object["type"] = i
  265. }
  266. } else { //中标金额
  267. findOfferFlag := false
  268. if offerReg.MatchString(k) && !strings.Contains(k, "费率") {
  269. findOfferFlag = true
  270. } else {
  271. kvTags := GetKvTags([]*util.Kv{&util.Kv{Key: k, Value: v}}, "", []string{"中标金额"}, isSite, codeSite)
  272. if len(kvTags["中标金额"]) > 0 {
  273. findOfferFlag = true
  274. }
  275. }
  276. //找到了中标金额
  277. if findOfferFlag && object["entname"] != nil {
  278. val := wo.clear("中标金额", v+GetMoneyUnit(k, v))
  279. if val != nil {
  280. moneys := clear.ObjToMoney([]interface{}{val, ""})
  281. if len(moneys) > 0 {
  282. if vf, ok := moneys[0].(float64); ok && moneys[len(moneys)-1].(bool){
  283. object["price"] = float64(vf)
  284. }
  285. }
  286. }
  287. winners = append(winners, object)
  288. object = map[string]interface{}{}
  289. }
  290. }
  291. }
  292. if len(object) > 0 {
  293. winners = append(winners, object)
  294. }
  295. indexs := []*WinnerFlag{}
  296. //tym := make(map[int]bool, 0)
  297. for _, winner := range winners {
  298. indexs = append(indexs, &WinnerFlag{
  299. index: winner["sort"].(int),
  300. //ttype: winner["type"].(int),
  301. })
  302. //tym[winner["type"].(int)] = true
  303. }
  304. //winnerFlag := wo.getMax(indexs, from)
  305. //if winnerFlag != nil {
  306. // winners = winners[winnerFlag.start : winnerFlag.end+1]
  307. //} else {
  308. // winners = []map[string]interface{}{}
  309. //}
  310. }
  311. return winners
  312. }
  313. //清理结果
  314. func (wo *WinnerOrderEntity) clear(typ, v string) interface{} {
  315. if typ == "中标单位" && regDivision.MatchString(v) {
  316. v = findCompanyReg.FindString(v)
  317. v = filterWinner.FindString(v)
  318. }
  319. v = filterValue.ReplaceAllString(v, "")
  320. //过滤
  321. return v //clear.ClearResult(typ, v)
  322. }
  323. //
  324. func (wo *WinnerOrderEntity) toNumber(value string, defaultNum int) int {
  325. value = numberReg.FindString(value)
  326. if value == "" {
  327. return defaultNum
  328. }
  329. v := util.ChineseNumberToInt(value)
  330. if v < 1 {
  331. v, _ = strconv.Atoi(value)
  332. }
  333. if v > 0 {
  334. return v
  335. }
  336. return defaultNum
  337. }
  338. //
  339. func (wo *WinnerOrderEntity) getMax(indexs []*WinnerFlag, from int) *WinnerFlag {
  340. allMap := map[int]*WinnerFlag{}
  341. max, start, textStart := -1, -1, -1
  342. isContinue := false
  343. flag := false
  344. is := []int{}
  345. for k, winnerFlag := range indexs {
  346. v := winnerFlag.index
  347. //从1开始,1前面的过滤掉
  348. if v == 1 {
  349. flag = true
  350. }
  351. if !flag {
  352. continue
  353. }
  354. if v == 1 {
  355. start = k
  356. textStart = winnerFlag.textStart
  357. isContinue = false
  358. }
  359. if isContinue {
  360. continue
  361. }
  362. nextIndex := 0
  363. if k < len(indexs)-1 {
  364. nextIndex = indexs[k+1].index
  365. }
  366. //从1-n是一组,遇到小于n的从新添加分组,分组不是1开头的过滤掉
  367. is = append(is, winnerFlag.textStart, winnerFlag.textEnd)
  368. if nextIndex-v != 1 {
  369. isContinue = true
  370. if max < k-start {
  371. max = k - start
  372. allMap[k-start] = &WinnerFlag{
  373. textStart: textStart,
  374. textEnd: winnerFlag.textEnd,
  375. start: start,
  376. end: k,
  377. max: max,
  378. indexs: is,
  379. }
  380. }
  381. }
  382. }
  383. if max != -1 {
  384. if from != 3 && len(allMap[max].indexs) <= 2 {
  385. return nil
  386. }
  387. return allMap[max]
  388. }
  389. return nil
  390. }
  391. //如果有两个,看第一个有几个换行,用第一个里面的最后一个换行作为第二个的结束位置
  392. //如果有两个以上,取前两个中换行最多的最后一个换行,作为其他的结束位置
  393. func (wo *WinnerOrderEntity) interceptText(indexs []int, con string) int {
  394. if len(indexs) == 1 {
  395. return 0
  396. }
  397. count := 0
  398. for ik, iv := range indexs {
  399. text := ""
  400. if ik < len(indexs)-1 {
  401. text = con[iv:indexs[ik+1]]
  402. } else {
  403. text = con[iv:]
  404. }
  405. //如果两个
  406. if len(indexs) == 2 {
  407. //取第一个有几个换行符
  408. if ik == 0 {
  409. count = len(regSpliteSegment.FindAllStringIndex(text, -1))
  410. }
  411. } else {
  412. //多个,取前两个中换行符最多的
  413. if ik <= 1 {
  414. thisCount := len(regSpliteSegment.FindAllStringIndex(text, -1))
  415. if thisCount > count {
  416. count = thisCount
  417. }
  418. }
  419. }
  420. }
  421. return count
  422. }
  423. //排序
  424. func (wo *WinnerOrderEntity) Order(winnerOrder []map[string]interface{}) {
  425. if winnerOrder == nil || len(winnerOrder) <= 1 {
  426. return
  427. }
  428. for x, _ := range winnerOrder {
  429. for y := 0; y < len(winnerOrder)-x-1; y++ {
  430. dt1, xok := winnerOrder[y]["sort"].(int)
  431. dt2, yok := winnerOrder[y+1]["sort"].(int)
  432. if xok && yok && dt1 > dt2 {
  433. temp := winnerOrder[y]
  434. winnerOrder[y] = winnerOrder[y+1]
  435. winnerOrder[y+1] = temp
  436. }
  437. }
  438. }
  439. }
  440. //合并
  441. func (wo *WinnerOrderEntity) Merge(winnerOrder, wors []map[string]interface{}) {
  442. if wors == nil || len(wors) == 0 {
  443. return
  444. }
  445. for _, v := range wors {
  446. for _, tv := range winnerOrder {
  447. sort, _ := v["sort"].(int)
  448. t_sort, _ := tv["sort"].(int)
  449. if sort == 0 || sort != t_sort {
  450. continue
  451. }
  452. if qutil.ObjToString(tv["entname"]) == "" && qutil.ObjToString(v["entname"]) != "" {
  453. tv["entname"] = v["entname"]
  454. }
  455. t_price, _ := tv["price"].(float64)
  456. price, _ := v["price"].(float64)
  457. if t_price == 0 && price != 0 {
  458. tv["price"] = v["price"]
  459. }
  460. }
  461. }
  462. }