whatlanggo.go 6.7 KB

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