whatlanggo.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package language
  2. import (
  3. "github.com/abadojack/whatlanggo"
  4. "github.com/allanpk716/ChineseSubFinder/pkg/types/language"
  5. "github.com/allanpk716/ChineseSubFinder/pkg/types/subparser"
  6. )
  7. // WhichChineseType 是简体中文(1)还是繁体中文(2),如果都不是,那么是 0
  8. func WhichChineseType(inputString string) int {
  9. info := whatlanggo.DetectWithOptions(inputString, GetLangOptions())
  10. // 是否是中文(简体、繁体)
  11. if info.Lang == whatlanggo.Cmn {
  12. // 判断是简体还是繁体
  13. if ChDict.IsChs(inputString, 0.9) == true {
  14. return 1
  15. } else {
  16. return 2
  17. }
  18. }
  19. return 0
  20. }
  21. // GetLangOptions 语言识别的 Options Whitelist
  22. func GetLangOptions() whatlanggo.Options {
  23. return whatlanggo.Options{
  24. Whitelist: map[whatlanggo.Lang]bool{
  25. whatlanggo.Cmn: true, // 中文 11
  26. whatlanggo.Eng: true, // 英文 15
  27. whatlanggo.Jpn: true, // 日文 32
  28. whatlanggo.Kor: true, // 韩文 37
  29. },
  30. }
  31. }
  32. // IsWhiteListLang 是否是白名单语言
  33. func IsWhiteListLang(lang whatlanggo.Lang) bool {
  34. switch lang {
  35. // 中文 英文 日文 韩文
  36. case whatlanggo.Cmn, whatlanggo.Eng, whatlanggo.Jpn, whatlanggo.Kor:
  37. return true
  38. default:
  39. return false
  40. }
  41. }
  42. // DetectSubLangAndStatistics 检测语言然后统计
  43. func DetectSubLangAndStatistics(oneDialogue subparser.OneDialogue, langDict map[int]int,
  44. usefulDialogueEx *[]subparser.OneDialogueEx, chLines *[]string, otherLines *[]string) int {
  45. var oneDialogueEx subparser.OneDialogueEx
  46. oneDialogueEx.StartTime = oneDialogue.StartTime
  47. oneDialogueEx.EndTime = oneDialogue.EndTime
  48. emptyLine := 0
  49. for _, line := range oneDialogue.Lines {
  50. if line == "" {
  51. emptyLine++
  52. continue
  53. }
  54. info := whatlanggo.DetectWithOptions(line, GetLangOptions())
  55. tmpLang := -1
  56. if IsWhiteListLang(info.Lang) == true {
  57. tmpLang = (int)(info.Lang)
  58. }
  59. // 这一种语言的 key 是否存在,不存在则新建,存在再数值 +1
  60. value, ok := langDict[tmpLang]
  61. if ok == true {
  62. // 累加
  63. value++
  64. langDict[tmpLang] = value
  65. } else {
  66. langDict[tmpLang] = 1
  67. }
  68. // 统计中文有多少行
  69. if info.Lang == whatlanggo.Cmn {
  70. *chLines = append(*chLines, line)
  71. } else {
  72. *otherLines = append(*otherLines, line)
  73. }
  74. // 这里可能是一个 dialogue 里面有两句话,而且两句话都是一个类型的语言,所以其实需要的是合并
  75. switch info.Lang {
  76. case whatlanggo.Cmn:
  77. oneDialogueEx.ChLine += line + " "
  78. case whatlanggo.Eng:
  79. oneDialogueEx.EnLine += line + " "
  80. case whatlanggo.Kor:
  81. oneDialogueEx.KrLine += line + " "
  82. case whatlanggo.Jpn:
  83. oneDialogueEx.JpLine += line + " "
  84. }
  85. }
  86. *usefulDialogueEx = append(*usefulDialogueEx, oneDialogueEx)
  87. return emptyLine
  88. }
  89. // SubLangStatistics2SubLangType 由分析的信息转换为具体是什么字幕的语言类型
  90. func SubLangStatistics2SubLangType(countLineFeed, AllLines float32, langDict map[int]int, chLines []string) language.MyLanguage {
  91. const basePer = 0.8
  92. // 是否是双语?
  93. isDouble := false
  94. perLines := countLineFeed / AllLines
  95. // 第二行字幕出现的概率大于 80% 应该稳了吧,不然还能三语?
  96. if perLines > basePer {
  97. isDouble = true
  98. }
  99. // 中文(包含了 chs 以及 cht,这一级是无法区分的,需要额外的简体和繁体区分方法)
  100. countChinese, hasChinese := langDict[int(whatlanggo.Cmn)]
  101. // 英文
  102. countEnglish, hasEnglish := langDict[int(whatlanggo.Eng)]
  103. // 日文
  104. countJapanese, hasJapanese := langDict[int(whatlanggo.Jpn)]
  105. // 韩文
  106. countKorean, hasKorean := langDict[int(whatlanggo.Kor)]
  107. // 0 - No , 1 - Chs, 2 - Cht
  108. isNoOrChsOrCht := 0
  109. isChsCount := 0
  110. if hasChinese {
  111. for _, line := range chLines {
  112. // 判断是简体还是繁体
  113. if ChDict.IsChs(line, 0.9) == true {
  114. isChsCount++
  115. }
  116. }
  117. // 简体句子的占比超过 80%
  118. if float32(isChsCount)/float32(len(chLines)) > 0.8 {
  119. isNoOrChsOrCht = 1
  120. } else {
  121. isNoOrChsOrCht = 2
  122. }
  123. }
  124. // 这里有一种情况,就是双语的字幕不是在一个时间轴上的,而是分成两个时间轴的
  125. // 那么之前的 isDouble 判断就失效了,需要补判一次
  126. if isDouble == false {
  127. if hasChinese && hasEnglish {
  128. isDouble = isDoubleLang(countChinese, countEnglish)
  129. }
  130. if hasChinese && hasJapanese {
  131. isDouble = isDoubleLang(countChinese, countJapanese)
  132. }
  133. if hasChinese && hasKorean {
  134. isDouble = isDoubleLang(countChinese, countKorean)
  135. }
  136. }
  137. // 优先判断双语
  138. if isDouble == true {
  139. // 首先得在外面统计就知道是双语
  140. if hasChinese && hasEnglish {
  141. // 简体 英文
  142. return chIsChsOrCht(language.ChineseSimpleEnglish, isNoOrChsOrCht)
  143. } else if hasChinese && hasJapanese {
  144. // 简体 日文
  145. return chIsChsOrCht(language.ChineseSimpleJapanese, isNoOrChsOrCht)
  146. } else if hasChinese && hasKorean {
  147. // 简体 韩文
  148. return chIsChsOrCht(language.ChineseSimpleKorean, isNoOrChsOrCht)
  149. } else if hasChinese {
  150. return chIsChsOrCht(language.ChineseSimple, isNoOrChsOrCht)
  151. } else if hasEnglish {
  152. return language.English
  153. } else if hasJapanese {
  154. return language.Japanese
  155. } else if hasKorean {
  156. return language.Korean
  157. } else {
  158. return language.Unknown
  159. }
  160. } else {
  161. // 如果比例达不到,那么就是单语言,所以最多的那个就是当前的语言
  162. // 这里的字典是有可能出现
  163. /*
  164. 这里的 AllLines 需要考虑一点,字幕内有很多特殊的背景声音旁白
  165. 那么会再上面提出的时候,直接把这一句话设置为空,那么这里所有的对白数量应该减去这些被检测为空的对白
  166. */
  167. if hasChinese {
  168. // 那么起码要占比 80% 对吧
  169. perLines = float32(countChinese) / AllLines
  170. if perLines > basePer {
  171. return chIsChsOrCht(language.ChineseSimple, isNoOrChsOrCht)
  172. }
  173. }
  174. if hasEnglish {
  175. // 那么起码要占比 80% 对吧
  176. perLines = float32(countEnglish) / AllLines
  177. if perLines > basePer {
  178. return language.English
  179. }
  180. }
  181. if hasJapanese {
  182. // 那么起码要占比 80% 对吧
  183. perLines = float32(countJapanese) / AllLines
  184. if perLines > basePer {
  185. return language.Japanese
  186. }
  187. }
  188. if hasKorean {
  189. // 那么起码要占比 80% 对吧
  190. perLines = float32(countKorean) / AllLines
  191. if perLines > basePer {
  192. return language.Korean
  193. }
  194. }
  195. return language.Unknown
  196. }
  197. }
  198. // 跟中文相关的再使用,其他的无需传入
  199. func chIsChsOrCht(inLanguage language.MyLanguage, isNoOrChsOrCht int) language.MyLanguage {
  200. // 输出原来的
  201. if isNoOrChsOrCht == 0 || isNoOrChsOrCht == 1 {
  202. return inLanguage
  203. }
  204. switch inLanguage {
  205. case language.ChineseSimpleEnglish:
  206. // 简体 英文
  207. return language.ChineseTraditionalEnglish
  208. case language.ChineseSimpleJapanese:
  209. // 简体 日文
  210. return language.ChineseTraditionalJapanese
  211. case language.ChineseSimpleKorean:
  212. // 简体 韩文
  213. return language.ChineseTraditionalKorean
  214. case language.ChineseSimple:
  215. // 简体
  216. return language.ChineseTraditional
  217. default:
  218. return inLanguage
  219. }
  220. }
  221. func isDoubleLang(count0, count1 int) bool {
  222. if count0 >= count1 {
  223. f := float32(count0) / float32(count1)
  224. if f >= 1 && f <= 1.4 {
  225. return true
  226. } else {
  227. return false
  228. }
  229. } else {
  230. f := float32(count1) / float32(count0)
  231. if f >= 1 && f <= 1.4 {
  232. return true
  233. } else {
  234. return false
  235. }
  236. }
  237. }