mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-03 20:26:36 +08:00
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package rule
|
||
|
||
import (
|
||
"regexp"
|
||
"strconv"
|
||
)
|
||
|
||
// 中文数字 → 阿拉伯数字,用于 java.toNumChapter。
|
||
//
|
||
// 对应 legado 的 `AppPattern.titleNumPattern` + `StringUtils.stringToInt`:把
|
||
// 「第一百零八章」规整成「第108章」。书源用它统一章节标题(排序/去重)。
|
||
// 解析不出来时原样返回,不做猜测。
|
||
var chapterTokenRe = regexp.MustCompile(`[0-9]+|[〇零一二三四五六七八九十百千万两兩]+`)
|
||
|
||
var (
|
||
zhDigits = map[rune]int{'〇': 0, '零': 0, '一': 1, '二': 2, '两': 2, '兩': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9}
|
||
zhUnits = map[rune]int{'十': 10, '百': 100, '千': 1000}
|
||
zhBigUnits = map[rune]int{'万': 10000, '億': 100000000, '亿': 100000000}
|
||
)
|
||
|
||
// numChapter 把标题里第一处数字规整成阿拉伯数字。
|
||
func numChapter(s string) string {
|
||
loc := chapterTokenRe.FindStringIndex(s)
|
||
if loc == nil {
|
||
return s
|
||
}
|
||
n, ok := parseCNSNum(s[loc[0]:loc[1]])
|
||
if !ok {
|
||
return s
|
||
}
|
||
return s[:loc[0]] + strconv.Itoa(n) + s[loc[1]:]
|
||
}
|
||
|
||
// parseCNSNum 解析纯阿拉伯数字或中文数字;无法解析返回 false。
|
||
func parseCNSNum(tok string) (int, bool) {
|
||
if tok == "" {
|
||
return 0, false
|
||
}
|
||
if n, err := strconv.Atoi(tok); err == nil {
|
||
return n, true
|
||
}
|
||
// 全是数字字符(如「一〇二」这种按位念法)→ 逐位拼起来
|
||
if digitsOnly(tok) {
|
||
n := 0
|
||
for _, r := range tok {
|
||
n = n*10 + zhDigits[r]
|
||
}
|
||
return n, true
|
||
}
|
||
total, section, num := 0, 0, 0
|
||
seen := false
|
||
for _, r := range tok {
|
||
if d, ok := zhDigits[r]; ok {
|
||
num = d
|
||
seen = true
|
||
continue
|
||
}
|
||
if u, ok := zhUnits[r]; ok {
|
||
if num == 0 {
|
||
num = 1 // 「十二」这类省略了前导一的写法
|
||
}
|
||
section += num * u
|
||
num = 0
|
||
seen = true
|
||
continue
|
||
}
|
||
if big, ok := zhBigUnits[r]; ok {
|
||
section += num
|
||
if section == 0 {
|
||
section = 1
|
||
}
|
||
total += section * big
|
||
section, num = 0, 0
|
||
seen = true
|
||
continue
|
||
}
|
||
return 0, false
|
||
}
|
||
if !seen {
|
||
return 0, false
|
||
}
|
||
return total + section + num, true
|
||
}
|
||
|
||
// digitsOnly 判断字符串是否只由中文数字字符组成。
|
||
func digitsOnly(s string) bool {
|
||
for _, r := range s {
|
||
if _, ok := zhDigits[r]; !ok {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|