From aa24e541202a6641c5498abd2be0615e44550429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Tue, 11 Aug 2026 11:52:08 +0800 Subject: [PATCH] 1 --- common/kg_name_normalize.go | 99 +++++++++++++++++++++++++++++++++++++ kb/consts/kg_alias.go | 28 +++++++++++ 2 files changed, 127 insertions(+) create mode 100644 common/kg_name_normalize.go create mode 100644 kb/consts/kg_alias.go diff --git a/common/kg_name_normalize.go b/common/kg_name_normalize.go new file mode 100644 index 0000000..a21b181 --- /dev/null +++ b/common/kg_name_normalize.go @@ -0,0 +1,99 @@ +package common + +import ( + "strings" + "unicode" +) + +// NormalizeKgTerm 知识图谱术语归一化(实体名与关系谓词共用,别名表由调用方传入)。 +// 幂等:NormalizeKgTerm(NormalizeKgTerm(x)) == NormalizeKgTerm(x)。 +// 规则保守,只做高置信合并,不做模糊相似度合并,防误合并("人民法院"与"最高人民法院"绝不合并)。 +// 返回空串表示归一化后无意义(调用方应丢弃);原本合法但归一化后为空时保留原名(如"中华人民共和国")。 +func NormalizeKgTerm(name string, aliasMap map[string]string) string { + orig := name + s := strings.TrimSpace(name) + s = fullToHalf(s) + s = strings.Join(strings.Fields(s), " ") + s = strings.Trim(s, "《》") + // 去版本注记括号及内容:内容含 年/修正/修订/施行/数字 才剥(人名限定语"张三(北京分公司)"不剥) + s = stripVersionParens(s) + s = strings.TrimRight(s, "。,;、!?,;!?.·。、") + s = strings.TrimSpace(s) + // 去"中华人民共和国"前缀(仅前缀;去完为空则保留原名,防实体"中华人民共和国"被删) + if strings.HasPrefix(s, "中华人民共和国") { + if rest := strings.TrimSpace(strings.TrimPrefix(s, "中华人民共和国")); rest != "" { + s = rest + } + } + // 别名全串精确映射(非 contains 替换,防"民诉法"吃掉"民诉法解释") + if std, ok := aliasMap[s]; ok && std != "" { + s = std + } + if s == "" && orig != "" { + return orig + } + return s +} + +// fullToHalf 全角转半角(ASCII 可见区 U+FF01~U+FF5E → U+21~U+7E,全角空格 → 半角空格) +func fullToHalf(s string) string { + return strings.Map(func(r rune) rune { + switch { + case r == ' ': + return ' ' + case r >= '!' && r <= '~': + return r - '!' + '\x21' + } + return r + }, s) +} + +// stripVersionParens 剥去含版本注记的括号及内容。注记判定:内容含 年/修正/修订/施行 或任一数字。 +func stripVersionParens(s string) string { + pairs := [][2]rune{{'(', ')'}, {'(', ')'}, {'【', '】'}, {'[', ']'}, {'〔', '〕'}} + var out strings.Builder + runes := []rune(s) + for i := 0; i < len(runes); { + stripped := false + for _, p := range pairs { + if runes[i] == p[0] { + end := findCloseParen(runes, i, p[1]) + if end > i && isVersionNote(runes[i+1:end]) { + i = end + 1 + stripped = true + break + } + } + } + if !stripped { + out.WriteRune(runes[i]) + i++ + } + } + return out.String() +} + +func findCloseParen(runes []rune, start int, close rune) int { + for j := start + 1; j < len(runes); j++ { + if runes[j] == close { + return j + } + } + return -1 +} + +// isVersionNote 括号内容是否版本注记(年/修正/修订/施行 或数字) +func isVersionNote(content []rune) bool { + for _, r := range content { + if unicode.IsDigit(r) { + return true + } + } + text := string(content) + for _, kw := range []string{"年", "修正", "修订", "施行"} { + if strings.Contains(text, kw) { + return true + } + } + return false +} diff --git a/kb/consts/kg_alias.go b/kb/consts/kg_alias.go new file mode 100644 index 0000000..688d1fb --- /dev/null +++ b/kb/consts/kg_alias.go @@ -0,0 +1,28 @@ +package consts + +// KgAliasMap 法律领域实体常见简称/变体 → 标准名(标准名统一为短形式,与归一化的 +// 去「中华人民共和国」前缀规则方向一致,保证幂等)。 +// 供 common.NormalizeKgTerm 传入做全串精确映射(调用方取用,common 不依赖本包)。 +// 规则:只收录高置信映射(全称/简称、明示别称),禁止模糊近似(防误合并)。 +// 新数据集出现新的别名规律时在此补充。 +var KgAliasMap = map[string]string{ + "民诉法": "民事诉讼法", + "刑诉法": "刑事诉讼法", + "治安处罚法": "治安管理处罚法", + "治安管理法": "治安管理处罚法", + "最高法院": "最高人民法院", + "最高法": "最高人民法院", + "高法": "最高人民法院", +} + +// KgPredicateAliasMap 关系谓词变体 → 标准谓词(同义合并,减少"发布/颁布"类重复边)。 +// 只收语义等价的映射;"依据/按照/根据"等近似义不合并。 +var KgPredicateAliasMap = map[string]string{ + "颁布": "发布", + "施行": "实施", + "实行": "实施", + "规定了": "规定", + "规定有": "规定", + "作出的规定": "规定", + "予以规定": "规定", +}