package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/cespare/xxhash/v2"
"go.mongodb.org/mongo-driver/bson"
"go.uber.org/zap"
"golang.org/x/net/html"
"jygit.jydev.jianyu360.cn/data_processing/common_utils"
"jygit.jydev.jianyu360.cn/data_processing/common_utils/log"
"jygit.jydev.jianyu360.cn/data_processing/common_utils/mongodb"
"jygit.jydev.jianyu360.cn/data_processing/common_utils/udp"
"math"
"net"
"os"
"regexp"
"sort"
"strings"
"time"
"unicode"
"unicode/utf8"
)
// convertToMongoID convertToMongoID
func convertToMongoID(query map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
if query == nil {
return result
}
idMap := query["_id"].(map[string]interface{})
if idMap != nil {
tmpQ := map[string]interface{}{}
for c, id := range idMap {
if idStr, ok := id.(string); ok && id != "" {
tmpQ[c] = mongodb.StringTOBsonId(idStr)
}
}
result["_id"] = tmpQ
}
return result
}
// StringSliceValuesEqual 判断切片相等
func StringSliceValuesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
sort.Strings(a)
sort.Strings(b)
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// Float64SliceSum float64 数据求和
func Float64SliceSum(nums []float64) float64 {
sum := 0.0
for _, num := range nums {
sum += num
}
return sum
}
func Float64Equal1Precision(a, b float64) bool {
return int(math.Round(a*10)) == int(math.Round(b*10))
}
// chargeType 判断mongo 字段类型和 es 字段类型相匹配
func chargeType(ftype, etype string) bool {
if ftype != "" {
switch ftype {
case "string":
if etype == "keyword" || etype == "text" {
return true
} else {
return false
}
case "bool":
if etype == "boolean" {
return true
} else {
return false
}
case "int64", "int32", "int":
if etype == "long" || etype == "integer" {
return true
} else {
return false
}
case "float64", "float32":
if etype == "double" || etype == "float" {
return true
} else {
return false
}
}
}
return false
}
// IsHanStart 判断字符串是否以汉字开头或者以字母开头
func IsHanStart(s string) bool {
if s == "" {
return false
}
return unicode.Is(unicode.Scripts["Han"], []rune(s)[0]) || unicode.IsLetter([]rune(s)[0])
}
// 判断字符是否为汉字
func IsHan(c rune) bool {
return unicode.Is(unicode.Scripts["Han"], c)
}
// 判断公司名称是否以圆括号开头且括号内汉字开头
func IsBracketStartWithHan(s string) bool {
if len(s) == 0 || s[0] != '(' {
return false
}
// 索引 i 和 j 分别是左右圆括号的位置,如果找不到右圆括号则返回 false
i, j := 0, 0
for j = i + 1; j < len(s); j++ {
if s[j] == ')' {
break
}
}
if j >= len(s) {
return false
}
// 检查圆括号内是否以汉字或字母开头
bracketContent := s[i+1 : j]
if len(bracketContent) == 0 || (!unicode.IsLetter(rune(bracketContent[0])) && !IsHan([]rune(bracketContent)[0])) {
return false
}
return true
}
// IsCompanyName 判断字符串是否以汉字开头、以括号开头并且括号里面是汉字、以"公司"结尾,其中一个条件符合即返回true,否则返回false
func IsCompanyName(s string) bool {
r := []rune(s)
//if len(r) >= 6 && (string(r[len(r)-6:]) == "有限公司" || string(r[len(r)-6:]) == "股份有限公司") {
// return (IsHanStart(s) || IsBracketStartWithHan(s))
//} else if len(r) >= 2 && string(r[len(r)-2:]) == "公司" {
// return (IsHanStart(s) || IsBracketStartWithHan(s))
//}
if len(r) > 2 {
return (IsHanStart(s) || IsBracketStartWithHan(s))
}
return false
}
// GetChineseCharacters 提取字符串中的汉字
func GetChineseCharacters(s string) string {
re := regexp.MustCompile(`[\p{Han}]+`)
return re.FindString(s)
}
func getCompanyName(name string) string {
if IsCompanyName(name) {
return name
}
return GetChineseCharacters(name)
}
func IsUnicodeStart(s string) bool {
if len(s) == 0 {
return false
}
_, size := utf8.DecodeRuneInString(s)
return size > 0
}
// RemoveDuplicateSuffix 去除字符串末尾的重复字词
func RemoveDuplicateSuffix(str string, suffix string) string {
// 构建正则表达式:^(.*?)(重复的结尾词)+$
re := regexp.MustCompile(fmt.Sprintf(`^(.*?)(%s)+$`, suffix))
matches := re.FindStringSubmatch(str)
if len(matches) == 3 {
return matches[1] + matches[2]
}
return str
}
func findName(name string) []map[string]interface{} {
filter := bson.M{"name": name, "status": 1}
info, _ := MgoB.Find("wcc_buyer", filter, nil, nil, false, -1, -1)
return *info
}
func findNameID(id string) []map[string]interface{} {
filter := bson.M{"name_id": id, "status": 1}
info, _ := MgoB.Find("wcc_buyer", filter, nil, nil, false, -1, -1)
return *info
}
// isStringRepeating 判断字符串内字符完全重复,例如:山东大学山东大学
func isStringRepeating(str string) bool {
for i := 0; i < len(str); i++ {
for j := i + 1; j < len(str); j++ {
if str[i] != str[j] {
return false
}
}
}
return true
}
// IsInStringArray 判断数组中是否存在字符串
func IsInStringArray(str string, arr []string) bool {
// 先对字符串数组进行排序
sort.Strings(arr)
// 使用二分查找算法查找字符串
pos := sort.SearchStrings(arr, str)
// 如果找到了则返回 true,否则返回 false
return pos < len(arr) && arr[pos] == str
}
// checkName 检查名称,不符合的返回false
func checkName(name string) (res bool) {
res = true
faleNames := []string{"管理有限公司", "有限公司", "技术公司", "制水公司", "工程有限公司", "耐材公司", "检测公司", "某公司", "现对公司", "集装箱码头分公司", "质检分公司", "司公司", "供电分公司", "建设公司", "水城分公司", "工信公司", "棉纺公司", "安装公司", "管公司", "测试公司", "四公司", "电力分公司",
"原平分公司", "兰州分公司", "基础设施公司", "陆丰分公司", "郴州分公司", "大渡口分公司", "汽车四分公司", "州大学", "开有限公司", "中小学幼儿园", "上级公司下级公司", "楼及幼儿园", "冷询有限公司", "市第一医院", "发展有阶公司", "楼及号地幼儿园", "第一幼儿园", "楼急救中心", "住宅楼及局", "号国际钻井公司", "管理委员会",
"区地块幼儿园", "省人民政府", "具有国家铁路局", "住宅楼及幼儿园", "丿再生资源技术有限公司", "为保证医院", "网及灾备中心", "地块幼儿园", "求石油昆仑燃气限公司", "栋楼及幼儿园", "号固井压裂公司", "号吐哈钻井公司", "股为限公司", "住宅楼及社区服务中心", "井与分公司", "场监督管局", "为了保证本次政府",
"人民政府东环街遂办事处", "龙湖区分公司", "澄海侨史馆", "中国移动科", "中国移动学院", "中国移动分公司"}
for _, v := range faleNames {
if name == v {
res = false
break
}
}
if len([]rune(name)) < 6 {
if strings.HasSuffix(name, "公司") {
res = false
} else if strings.HasSuffix(name, "办事处") {
res = false
} else if strings.HasSuffix(name, "分公司") {
res = false
} else if strings.HasSuffix(name, "管委会") {
res = false
} else if strings.HasSuffix(name, "支行") {
res = false
} else if strings.HasSuffix(name, "网络部") {
res = false
} else if strings.HasSuffix(name, "部队") {
res = false
} else if strings.HasSuffix(name, "医科大学") {
res = false
}
}
if len([]rune(name)) < 7 && strings.HasSuffix(name, "中医药大学") {
res = false
}
if !TDName(name) {
res = false
}
return
}
// TDName 根据开头、结尾、排除词,筛选名称,筛选不符合的数据
func TDName(name string) (res bool) {
res = true
if isStringRepeating(name) { //重复数据,山东大学山东大学
res = false
log.Info("TDName", zap.String("isStringRepeating", name))
return res
}
countWords := []string{"教育局", "学校", "大学", "中学", "审计局", "郑州局", "中医院", "部队", "有限公司"}
//教育局出现二次
for _, c := range countWords {
if strings.Count(name, c) > 1 {
res = false
log.Info("TDName", zap.String("countWords", c), zap.String("name", name))
return res
}
}
//公司出现三次,错误
if strings.Count(name, "公司") > 2 {
res = false
log.Info("TDName", zap.String("公司", "公司出现三次"))
return res
}
//公司出现 二次,但是不是分公司
if strings.Count(name, "公司") > 1 {
if !strings.Contains(name, "分公司") && !strings.Contains(name, "子公司") && !strings.Contains(name, "市公司") {
res = false
log.Info("TDName", zap.String("公司", "公司出现二次,但没有分公司, 子公司"))
return res
}
}
//开头的单词
preWords := []string{"取消", "转发", "省", "会议室", "某", "某单位", "某公司", "某学校", "测试", "某大学", "某医院", "拟建", "机械", "县", "市", "区", "巡察", "人民", "对", "楼", "家长", "春季", "于", "度", "初级中学", "州", "总部", "一号", "含", "育场", "选择", "第包", "医院",
"共赢资产", "从", "实验中学", "公共", "乘用车", "部与", "一直", "一体化", "现对", "现为", "之", "份", "半坡", "下属", "程", "信息", "带", "工务", "技术", "于", "号", "辖属", "造", "计财", "实验", "原", "器械", "是", "师", "雨山区", "云城区", "阜涣", "公联", "批",
"总承包", "姓市", "秋季学期", "哈巴河", "保险", "开发区", "尘设资", "团", "物业", "农村", "部", "东省", "于", "章", "董", "分局", "再", "微", "明", "建", "公司", "审计", "满足", "中学", "届", "大学", "按摩", "中心", "附属", "总", "教育局", "中学", "小学", "学院",
"中医院", "人医院", "学校", "输", "十六", "有限", "节能", "二公司", "分公司", "子公司", "公司", "审计", "河河", "地公司", "六公司", "三公司", "十六公司", "节能",
"股份", "运输公司", "堇", "家纺", "港区"}
// 开头
for _, word := range preWords {
if strings.HasPrefix(name, word) {
res = false
log.Info("TDName", zap.String("preWords", word), zap.String("name", name))
return res
}
}
//结尾单词
sufWords := []string{"市", "某单位", "某公司", "某学校", "测试", "某大学", "某医院", "地产鲨", "项目组", "研究", "公国司", "物资", "评估与医院", "年室", "招标", "设有", "复限公司", "服务", "有限责任", "罩套", "有阴公", "人队", "报告", "厕所", "污水处", "检查", "镇中心",
"显微镜", "段", "现场局", "租赁", "镇", "市中心", "勐阿糖厂", "展厅", "等医院", "广场室", "水利顷", "市室", "交界处", "自助银行", "若源局", "布局", "联合体", "气室", "活动场", "包装公司", "投资", "有限", "等", "设备", "急件", "有限公司有限公司", "公司公司", "分公司分公司",
"大学大学", "学院学院", "大学场", "学校室", "部队部队", "内部", "部分支公司"}
//结尾
for _, word := range sufWords {
if strings.HasSuffix(name, word) {
res = false
log.Info("TDName", zap.String("sufWords", word), zap.String("name", name))
return res
}
}
//包含的单词
falseWords := []string{"丿", "艹", "[ ", "【", "?", "亻", "#", "~", "^", "亻", "*", "$", "、", "/", "*", "<>", "[ ", "【", "?", "某", "病历系统", "不予", "薯公", "标段", "电压互感器", "我",
"省道", "询比", "学校和幼儿园", "住宅", "询价", "办公区", "项目", "中旎髓细兴", "办么", "测试", "项目部", "飞地园", "购", "鉴定", "实验室", "车务段", "可测性设计", "手术室", "第二期", "退", "催促",
"协议中", "影响", "工作", "动力厂", "干扰源", "指定", "达到", "控制器", "竞价", "人哥", "络络络", "路段", "示范区", "一般用", "采供", "修缮", "招标单位", "联系方式", "沟通", "配线架", "及配建",
"任务", "分包", "其他", "行为", "中标人", "教室", "安置", "暂行", "建设单位", "选聘", "合同", "转发", "勿救", "既有", "装置", "任务", "开展", "依据", "指定", "试剂", "景观", "包件", "法人", "合格",
"短管", "投标文件", "核实", "测汞仪", "黑名单", "制作类", "汇编", "收购", "拿", "丿", "艹", "关于", "要求", "举办", "显示所", "右阴公司", "发射", "加装", "复印纸", "终止", "生产处", "提供", "新建",
"该项目", "安装", "改造", "样品", "课室", "水毁道路", "闲置资产", "#", "南校园", "扩建", "道路维修", "等所", "维稳中心", "异议", "音乐厅", "慰问", "介入", "改建", "即", "建设", "某单位",
"医院医院", "中国电建中国电建", "建设建设", "建设规模", "满足", "郑州郑州", "学校学校", "&", ";", ";", "就医院", "酒医院", "至医院", "对", "所需", "提升", "提高", "学期", "学年", "规模", "必须",
"建成", "各公司", "公司与公司", "公司的公司", "公司办公司", "养护"}
// 包含
for _, word := range falseWords {
if strings.Contains(name, word) {
res = false
log.Info("TDName", zap.String("falseWords", word), zap.String("name", name))
return res
}
}
return
}
// ruleBuyer 判断采购单位正确,名称错误返回true,名称正确返回false
func ruleBuyer(input string) (res bool) {
//开头的单词
preWords := []string{"转发", "省", "会议室", "某", "某单位", "某公司", "某学校", "测试", "某大学", "某医院", "拟建", "机械", "县", "市", "区", "巡察", "人民路", "对", "楼", "家长", "春季", "对", "度", "初级中学", "州", "总部", "一号", "含", "育场", "选择", "第包", "医院",
"共赢资产", "从", "实验中学", "公共", "乘用车", "部与", "一直", "一体化", "现对", "现为", "之", "份", "半坡", "下属", "程", "信息", "带", "工务", "技术", "于", "号", "辖属", "造", "计财", "实验", "原", "器械", "是", "师", "雨山区", "云城区", "阜涣", "公联", "批",
"总承包", "姓市", "秋季学期", "哈巴河", "保险", "开发区", "尘设资", "团", "物业", "农村", "部", "二", "后勤", "位于", "选定", "依法", "口", "代表", "这", "逝沮省", "上半年", "第一", "门市", "配套", "八月", "七月", "集回", "维修", "遴选", "但", "增加",
"取消", "采购", "一直", "一体化", "现对", "现为", "之", "份", "取消", "转发", "省", "会议室", "某", "某单位", "某公司", "某学校", "测试", "某大学", "某医院", "拟建", "机械", "县", "市", "区", "巡察", "人民", "对", "楼", "家长", "春季", "于", "度", "初级中学", "州", "总部", "一号", "含", "育场", "选择", "第包", "医院",
"共赢资产", "从", "实验中学", "公共", "乘用车", "部与", "一直", "一体化", "现对", "现为", "之", "份", "半坡", "下属", "程", "信息", "带", "工务", "技术", "于", "号", "辖属", "造", "计财", "实验", "原", "器械", "是", "师", "阜涣", "公联", "批",
"总承包", "姓市", "秋季学期", "哈巴河", "保险", "开发区", "尘设资", "团", "物业", "农村", "部", "东省", "于", "章", "董", "分局", "再", "微", "明", "建", "公司", "审计", "满足", "中学", "届", "大学", "按摩", "中心", "附属", "总", "教育局", "中学", "小学", "学院",
"中医院", "人医院", "学校", "输", "十六", "有限", "节能", "二公司", "分公司", "子公司", "公司", "审计", "河河", "地公司", "六公司", "三公司", "十六公司", "节能", "股份", "运输公司", "堇", "家纺", "港区", "检查"}
//开头关键词
for _, word := range preWords {
if strings.HasPrefix(input, word) {
res = true
return res
}
}
//结尾关键词
suffixes := []string{"院院", "局局", "场场", "小学室", "和社", "人屡政府", "谈话室", "小区局", "今作社", "点场", "人昆政府",
"年度室", "分行银行", "人政府", "人民矢院", "教学楼局", "笺理局", "地场", "人民唉院", "瞥理局", "所院", "农业衣村局",
"民丢局", "委员会老干部", "办非处", "等支局", "监督站局", "停车库局", "检查员", "办直处", "进行局", "楼局", "等局", "人民政府社",
"模块局", "人民政俯", "人民医标院", "农业农局", "园局", "规则局", "人乓政府", "人事条局", "箐理所", "在政府", "重点局", "大学入场",
"入场", "发也站", "赘源局", "计划生育服务中心政府", "第一人民吹院", "有限公司室", "教标育局", "一民政府", "场部", "埋局", "大学大学",
"分公司分公司", "医院医院", "测试", "市", "显微镜", "段", "现场局", "租赁"}
for _, word := range suffixes {
if strings.HasSuffix(input, word) {
res = true
return res
}
}
//包含的关键词
specials := []string{"丿", "艹", "[ ", "【", "?", "亻", "#", "~", "^", "亻", "*", "$", "、", "/", "*",
"<>", "[ ", "【", "?", "某", "我", "第一轮", "第一次", "第一词", "第一季", "各学校", "第一批", "完全学校",
"一致同意", "X", "保体障局", "人们政府", "上设局", "开发茎", "场场", "设保", "武鳖", "集回", "项日", "代理银行",
"辽宁省省会", "菖处", "口国", "人民汰院", "肉州市", "火车站社", "自然资源和规局", "萎员会", "经济技术开发茎",
"有限公司厂", "测试", "建设建设", "建设规模", "满足", "郑州郑州", "学校学校", "&", ";", ";",
"就医院", "酒医院", "至医院", "所需", "提升", "提高", "学期", "学年", "规模",
"拿", "艹", "关于", "要求", "举办", "右阴公司", "发射", "加装", "扩建", "道路维修", "等所",
"维稳中心", "异议", "任务", "分包", "其他", "行为", "中标人", "教室", "安置", "暂行", "选聘", "合同", "转发",
"勿救", "既有", "装置", "开展", "依据", "指定", "一般用", "采供", "修缮", "招标单位", "联系方式", "沟通",
"该项目", "安装", "样品", "课室", "水毁道路", "闲置资产", "某单位", "某公司", "某学校", "测试", "某大学", "某医院", "地产鲨", "项目组",
"公国司", "评估与医院", "年室", "招标", "设有", "复限公司", "罩套", "有阴公", "人队", "报告",
"显微镜", "现场局", "市中心", "勐阿糖厂", "展厅", "等医院", "广场室", "水利顷", "市室", "交界处", "自助银行",
"若源局", "布局", "联合体", "气室", "活动场", "包装公司", "急件", "核实", "测汞仪", "黑名单", "制作类",
"大学大学", "学院学院", "大学场", "学校室", "部队部队", "内部", "部分支公司", "短管", "投标文件", "汇编", "收购"}
for _, v := range specials {
if strings.Contains(input, v) {
res = true
return res
}
}
return res
}
// SendUdpMsg 通知处理企业新增数据
func SendUdpMsg(data map[string]interface{}, target *net.UDPAddr) {
bytes, _ := json.Marshal(data)
UdpClient.WriteUdp(bytes, udp.OP_TYPE_DATA, target)
log.Info("SendUdpMsg", zap.Any("data", data), zap.Any("target", target))
}
// deletePreEsData 删除预处理索引数据
//func deletePreEsData(preId string) {
// now := time.Now()
// month := int(time.Now().Month())
// monthStr := strconv.Itoa(month)
// year := time.Now().Year()
// yearStr := strconv.Itoa(year)
// //当前处理索引名称
// preBiddingIndex := fmt.Sprintf("bidding_%s%s", yearStr, monthStr)
// lastIndex := ""
//
// //按小时创建
// if config.Conf.Env.SpecType == "hour" {
// preBiddingIndex = preBiddingIndex + strconv.Itoa(now.Day()) + strconv.Itoa(now.Hour())
// last := now.Add(-time.Hour)
// month2 := int(last.Month())
// monthStr2 := strconv.Itoa(month2)
// year2 := last.Year()
// yearStr2 := strconv.Itoa(year2)
// dayStr2 := strconv.Itoa(last.Day())
// //上个索引名称
// lastIndex = "bidding_" + yearStr2 + monthStr2
// lastIndex = lastIndex + dayStr2 + strconv.Itoa(last.Hour())
//
// } else if config.Conf.Env.SpecType == "day" {
// //按天创建
// preBiddingIndex = preBiddingIndex + strconv.Itoa(time.Now().Day())
// last := now.AddDate(0, 0, -1)
// month2 := int(last.Month())
// monthStr2 := strconv.Itoa(month2)
// year2 := last.Year()
// yearStr2 := strconv.Itoa(year2)
// dayStr2 := strconv.Itoa(last.Day())
// //上个索引名称
// lastIndex = "bidding_" + yearStr2 + monthStr2
// lastIndex = lastIndex + dayStr2
//
// } else if config.Conf.Env.SpecType == "month" {
// // 月份;
// last := now.AddDate(0, -1, 0)
// month2 := int(last.Month())
// monthStr2 := strconv.Itoa(month2)
// year2 := last.Year()
// yearStr2 := strconv.Itoa(year2)
// //上个索引名称
// lastIndex = "bidding_" + yearStr2 + monthStr2
// }
//
// //删除预处理 索引数据
// if len(PreEs) == 0 {
// time.Sleep(time.Second)
// }
// for _, client := range PreEs {
// if client == nil {
// continue
// }
// // 老索引有数据
// if client.Count(lastIndex, nil) > 0 {
// err := client.DeleteByID(lastIndex, preId)
// if err != nil {
// fmt.Println("deletePreEsData: ", preId, err)
// }
// }
//
// err := client.DeleteByID(preBiddingIndex, preId)
// if err != nil {
// fmt.Println("deletePreEsData: ", preId, err)
// }
// }
//
//}
// saveDb 文件写入
//func saveDb() {
// mutex.Lock()
// defer mutex.Unlock()
// // 如果 cache 为空,则无需执行写入操作
// if cache == nil {
// log.Error("saveDb", zap.Any("cache", "为空"))
// }
//
// if cache.GetCardinality() > 0 {
// fo, err := os.OpenFile(*dbfile, os.O_CREATE|os.O_RDWR|os.O_SYNC|os.O_TRUNC, 0777)
// if err != nil {
// log.Info("saveDb", zap.Error(err))
// }
//
// defer fo.Close()
// _, err = cache.WriteTo(fo)
// if err != nil {
// log.Info("saveDb", zap.Any("cache.WriteTo", err))
// }
// }
//}
// saveDb 文件写入
func saveDb() {
mutex.Lock()
defer mutex.Unlock()
if cache == nil {
log.Error("saveDb", zap.String("cache", "为空"))
return
}
if cache.GetCardinality() == 0 {
log.Info("saveDb", zap.String("提示", "cache 为空,未保存"))
return
}
tmpFile := *dbfile + ".tmp"
bakFile := *dbfile + ".bak"
// 1. 写入临时文件
tmp, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
log.Error("saveDb", zap.String("创建 tmp 文件失败", tmpFile), zap.Error(err))
return
}
_, err = cache.WriteTo(tmp)
tmp.Close()
if err != nil {
log.Error("saveDb", zap.String("写入 tmp 文件失败", tmpFile), zap.Error(err))
return
}
// 2. 原文件备份(.bak)
if _, err := os.Stat(*dbfile); err == nil {
err = os.Rename(*dbfile, bakFile)
if err != nil {
log.Warn("备份失败", zap.String("源文件", *dbfile), zap.Error(err))
}
}
// 3. 原子替换新文件
err = os.Rename(tmpFile, *dbfile)
if err != nil {
log.Error("saveDb", zap.String("tmp 替换 dbfile 失败", ""), zap.Error(err))
return
}
log.Info("saveDb", zap.String("状态", "写入成功,主文件已更新"))
}
// getNewName 获取新的不重复名称
func getNewName(tmp map[string]interface{}) string {
projectName := util.ObjToString(tmp["projectname"])
projectCode := util.ObjToString(tmp["projectcode"])
buyer := util.ObjToString(tmp["buyer"])
firsttime := util.Int64All(tmp["firsttime"])
createtime := util.Int64All(tmp["createtime"])
var projectDate, createDate string
if firsttime > 0 {
projectDate = time.Unix(firsttime, 0).Format("2006-01-02")
}
if createtime > 0 {
createDate = time.Unix(createtime, 0).Format("2006-01-02")
}
var matchWords = make([]string, 0)
if list, ok := tmp["list"].([]interface{}); ok {
if len(list) > 0 {
for _, v := range list {
if da, ok := v.(map[string]interface{}); ok {
title := util.ObjToString(da["title"])
// 使用正则表达式进行匹配
matches := GetPackages(title)
for _, v := range matches {
if !IsInStringArray(v, matchWords) {
matchWords = append(matchWords, v)
}
}
}
}
}
}
//pks := removeDuplicates(matchWords)
packages := strings.Join(matchWords, "、")
return RenameProjectName(projectName, projectCode, packages, projectDate, buyer, createDate)
}
// hash 计算hash
func hash(src string) uint64 {
return xxhash.Sum64String(src)
}
// RenameProjectName 获取新的不重复的项目名称
func RenameProjectName(projectName, projectCode, packages, projectDate, buyer, createDate string) (newName string) {
//TODO 1.判断项目名称是否重复
var id uint64
defer func() {
if id > 0 && newName != "" {
cache.Add(uint32(id))
cacheModify = true
}
}()
//1.项目名称
if projectName != "" {
id = hash(projectName)
if !cache.Contains(uint32(id)) {
newName = projectName
return projectName
}
}
//TODO 2.1 项目名称+项目编码
if projectCode != "" {
newName = projectName + "_" + projectCode
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 2.2 项目名称+分包信息
if packages != "" {
newName = projectName + "_" + packages
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 2.3 项目名称+项目时间
if projectDate != "" {
newName = projectName + "_" + projectDate
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 2.4 项目名称+采购单位名称
if buyer != "" {
newName = projectName + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.1 项目名称+项目编码+分包信息
if projectCode != "" && packages != "" {
newName = projectName + "_" + projectCode + "_" + packages
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.2 项目名称+项目编码+项目时间
if projectCode != "" && projectDate != "" {
newName = projectName + "_" + projectCode + "_" + projectDate
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.3 项目名称+项目编码+采购单位
if projectCode != "" && buyer != "" {
newName = projectName + "_" + projectCode + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.4 项目名称+分包+项目时间
if packages != "" && projectDate != "" {
newName = projectName + "_" + packages + "_" + projectDate
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.5 项目名称+分包+采购单位
if packages != "" && buyer != "" {
newName = projectName + "_" + packages + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 3.6 项目名称+项目时间+采购单位
if projectDate != "" && buyer != "" {
newName = projectName + "_" + projectDate + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 4.1 项目名称+项目编码+分包信息+项目时间
if projectCode != "" && packages != "" && projectDate != "" {
newName = projectName + "_" + projectCode + "_" + packages + "_" + projectDate
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 4.2 项目名称+项目编码+分包信息+采购单位
if projectCode != "" && packages != "" && buyer != "" {
newName = projectName + "_" + projectCode + "_" + packages + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
}
//TODO 5 项目名称+项目编码+分包信息+项目时间+采购单位
if projectCode != "" && packages != "" && projectDate != "" && buyer != "" {
newName = projectName + "_" + projectCode + "_" + packages + "_" + projectDate + "_" + buyer
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
}
} else {
newName = projectName + "_" + projectCode + "_" + packages + "_" + projectDate + "_" + buyer + "_" + createDate
id = hash(newName)
if !cache.Contains(uint32(id)) {
return newName
} else {
newName = ""
}
}
return
}
// GetPackages 获取对应的分包
func GetPackages(title string) (res []string) {
// 定义正则表达式
rea := regexp.MustCompile(`包\d{1,2}[-~、]\d{1,2}|\d{1,2}[-~、]\d{1,2}包`) //1-6包;01-06包;01、02包;包1、包2
//text := "中国绿发投资集团有限公司直属项目公司2023年第20批集中采购非招标项目(包10、12、14、17、18、19"
packages := rea.FindAllString(util.ObjToString(title), -1) //匹配的包
if len(packages) > 0 {
res = append(res, packages...)
}
reb := regexp.MustCompile(`(标段[1-9一二三四五六七八九]|[1-9一二三四五六七八九]标段|包[1-9一二三四五六七八九]?[0-9]|[1-9一二三四五六七八九]?[0-9]包|[a-kA-K]包)`) // 标题只有一个包2
pgs := reb.FindAllString(title, -1)
if len(pgs) > 0 {
for _, v := range pgs {
if !IsInStringArray(v, res) {
res = append(res, v)
}
}
}
return res
}
// TagMatching 标签结构体
type TagMatching struct {
tagName string //标签名称
tagCode string //标签值(保存)
matchField []string //关键词匹配字段,title,detail
matchKey string //匹配的词语,多个使用逗号连接,"部队,国防,军事,军用"
matchKeyReg []*RegexpInfo //关键词的正则
addField []string //附加词匹配字段
addKey string //附件词匹配关键词
addKeyReg []*RegexpInfo //附加次的正则
excludeField []string //排除词匹配字段
excludeKey string //排除词匹配词
excludeKeyReg []*RegexpInfo //排除词正则
//clearKey []string //清理词匹配字段跟关键词一样
}
// RegexpInfo 关键词正则
type RegexpInfo struct {
keyStr string
regs *regexp.Regexp
}
// GetRegex 根据关键词或者对应正则
func GetRegex(key string) []*RegexpInfo {
var infos []*RegexpInfo
for _, s := range strings.Split(key, ",") {
if strings.Contains(s, "&&") || strings.Contains(s, "&!") {
info := &RegexpInfo{
keyStr: s,
regs: nil,
}
infos = append(infos, info)
} else {
info := &RegexpInfo{
keyStr: s,
regs: regexp.MustCompile(".*(?i)" + s + ".*"),
}
infos = append(infos, info)
}
}
return infos
}
// TaskTags 根据数据和正则规则,验证数据标签
func TaskTags(tmp map[string]interface{}, regs []TagMatching) (tags []string, keyWord, addWord string) {
// 在匹配字段里,比如标题满足了关键词,详情满足附加词,关键词的匹配字段含有标题,附加词的匹配字段含有详情;就符合条件
Loop:
for _, v := range regs {
keyR := false // 关键词匹配结果
addR := false //附加次匹配结果
// 1.排除词
if len(v.excludeField) > 0 && len(v.excludeKeyReg) > 0 {
// 遍历排除词对应的tmp字段信息
for _, f := range v.excludeField {
if val := util.ObjToString(tmp[f]); val != "" {
if rs, _ := getRegsResult(val, v.excludeKeyReg); rs {
//有排除词,直接判断下一个规则
continue Loop
}
}
}
}
// 清理词;目的把 类似 fuck的单词替换为空字符串
//if len(v.clearKey) > 0 && len(v.matchField) > 0 {
// for _, s := range v.clearKey {
// for _, f := range v.matchField {
// if val := util.ObjToString(tmp[f]); val != "" {
// tmp[f] = strings.ReplaceAll(val, s, "")
// }
// }
// }
//}
// 关键词
if len(v.matchField) > 0 && len(v.matchKeyReg) > 0 {
for _, f := range v.matchField {
if val := util.ObjToString(tmp[f]); val != "" {
if rs, da := getRegsResult(val, v.matchKeyReg); rs {
keyR = true
keyWord = da
//log.Print("key", da)
break
}
}
}
}
// 附加词
if len(v.addField) > 0 && len(v.addKeyReg) > 0 && keyR {
for _, f := range v.addField {
if val := util.ObjToString(tmp[f]); val != "" {
if rs, da := getRegsResult(val, v.addKeyReg); rs {
addR = true
addWord = da
//log.Println("add", da)
break
}
}
}
} else {
addR = true
}
// 满足 关键词和附加词条件
if keyR && addR {
// 去重相同标签
if !IsInStringArray(v.tagName, tags) {
tags = append(tags, v.tagName)
}
}
}
return
}
// getRegsResult 验证数据是否符合数组正则
func getRegsResult(data string, regs []*RegexpInfo) (res bool, a string) {
for _, e1 := range regs {
if e1.regs != nil && e1.regs.MatchString(data) {
return true, e1.regs.String()
} else {
// && 特殊处理
if strings.Contains(e1.keyStr, "&&") {
flag := true
for _, s := range strings.Split(e1.keyStr, "&&") {
if !strings.Contains(data, s) {
flag = false
break
}
}
if flag {
return true, e1.keyStr
}
}
// 前面是必须有的关键词&!,后面是不能有的关键词;比如 军队&!点军队,
if strings.Contains(e1.keyStr, "&!") {
keys := strings.Split(e1.keyStr, "&!")
if strings.Contains(data, keys[0]) && !strings.Contains(data, keys[1]) {
return true, e1.keyStr
}
}
}
}
return false, ""
}
// CleanHTMLTags 处理HTML内容并返回清理后的文本
func CleanHTMLTags(htmlContent string) (string, error) {
// 解析HTML内容
doc, err := html.Parse(strings.NewReader(htmlContent))
if err != nil {
return "", err
}
var buf bytes.Buffer
// 递归函数,用来遍历 HTML 树
var f func(*html.Node)
f = func(n *html.Node) {
// 处理文本节点
if n.Type == html.TextNode {
// 去掉文本节点中的所有空格
//buf.WriteString(n.Data)
// 去掉文本节点中的所有空格
trimmedText := strings.ReplaceAll(n.Data, " ", "") // 去掉所有空格
buf.WriteString(trimmedText)
}
// 处理元素节点
if n.Type == html.ElementNode {
// 调试:输出当前节点的类型和标签名
//fmt.Printf("ElementNode: %s\n", n.Data)
// 处理
标签,插入换行
if n.Data == "br" {
buf.WriteString("\n")
} else if n.Data == "table" {
// 处理表格标签
单元格 for td := tr.FirstChild; td != nil; td = td.NextSibling { if td.Data == "td" { buf.WriteString("[TD] ") f(td) // 递归处理 | 中的内容
}
}
}
}
//buf.WriteString("Table End\n")
} else if n.Data == "ul" {
// 处理无序列表
|