优化自动分段

pull/462/head
gedoor 4 years ago
parent 8558fe9916
commit 9fa734ab4c
  1. 111
      app/src/main/java/io/legado/app/help/ContentHelp.kt

@ -1,6 +1,7 @@
package io.legado.app.help package io.legado.app.help
import java.util.* import java.util.*
import java.util.regex.Pattern
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -30,6 +31,7 @@ object ContentHelp {
} else { } else {
content1 content1
} }
val dict = makeDict(content2)
var p = content2 var p = content2
.replace(""".toRegex(), "") .replace(""".toRegex(), "")
.replace("[::]['\"‘”“]+".toRegex(), ":“") .replace("[::]['\"‘”“]+".toRegex(), ":“")
@ -68,9 +70,7 @@ object ContentHelp {
buffer = StringBuffer((content1.length * 1.15).toInt()) buffer = StringBuffer((content1.length * 1.15).toInt())
for (s in p) { for (s in p) {
buffer.append("\n") buffer.append("\n")
buffer.append( buffer.append(findNewLines(s, dict))
findNewLines(s)
)
} }
buffer = reduceLength(buffer) buffer = reduceLength(buffer)
content1 = ("$chapterName\n\n" + buffer.toString() // 处理章节头部空格和换行 content1 = ("$chapterName\n\n" + buffer.toString() // 处理章节头部空格和换行
@ -178,10 +178,12 @@ object ContentHelp {
} }
// 对内容重新划分段落.输入参数str已经使用换行符预分割 // 对内容重新划分段落.输入参数str已经使用换行符预分割
private fun findNewLines(str: String): String { private fun findNewLines(str: String, dict: List<String>): String {
val string = StringBuffer(str) val string = StringBuffer(str)
// 标记string中每个引号的位置.特别的,用引号进行列举时视为只有一对引号。 如:“锅”、“碗”视为“锅、碗”,从而避免误断句。 // 标记string中每个引号的位置.特别的,用引号进行列举时视为只有一对引号。 如:“锅”、“碗”视为“锅、碗”,从而避免误断句。
val arrayQuote: MutableList<Int> = ArrayList() val arrayQuote: MutableList<Int> = ArrayList()
// 标记忽略的引号
val array_ignore_quote: List<Int> = ArrayList()
// 标记插入换行符的位置,int为插入位置(str的char下标) // 标记插入换行符的位置,int为插入位置(str的char下标)
var insN = ArrayList<Int>() var insN = ArrayList<Int>()
@ -201,7 +203,16 @@ object ContentHelp {
if (size > 0) { if (size > 0) {
val quotePre = arrayQuote[size - 1] val quotePre = arrayQuote[size - 1]
if (i - quotePre == 2) { if (i - quotePre == 2) {
if (match(",、,/", str[i - 1])) { var remove = false
if (waitClose) {
if (match(",,、/", str[i - 1])) {
// 考虑出现“和”这种特殊情况
remove = true
}
} else if (match(",,、/和与或", str[i - 1])) {
remove = true
}
if (remove) {
string.setCharAt(i, '“') string.setCharAt(i, '“')
string.setCharAt(i - 2, '”') string.setCharAt(i - 2, '”')
arrayQuote.removeAt(size - 1) arrayQuote.removeAt(size - 1)
@ -232,8 +243,10 @@ object ContentHelp {
} }
} }
} }
// if(char_b2=='.' || char_b2=='。') //if(char_b2=='.' || char_b2=='。')
if (match(MARK_SENTENCES_END_P, charB2)) insN.add(p - 1) else { if (match(MARK_SENTENCES_END_P, charB2)) {
insN.add(p - 1)
} else if (!match("", charB2)) {
val lastEnd = seekLast(str, MARK_SENTENCES_END, i, lastQuote) val lastEnd = seekLast(str, MARK_SENTENCES_END, i, lastQuote)
if (lastEnd > 0) insN.add(lastEnd) else insN.add(lastQuote) if (lastEnd > 0) insN.add(lastEnd) else insN.add(lastQuote)
} }
@ -258,16 +271,15 @@ object ContentHelp {
val size = arrayQuote.size val size = arrayQuote.size
// 标记循环状态,此位置前的引号是否已经配对 //标记循环状态,此位置前的引号是否已经配对
var opend = false var opend = false
if (size > 0) { if (size > 0) {
//第1次遍历array_quote,令其元素的值不为0
// 第1次遍历array_quote,令其元素的值不为0
for (i in 0 until size) { for (i in 0 until size) {
if (mod[i] > 0) { if (mod[i] > 0) {
opend = true opend = true
} else if (mod[i] < 0) { } else if (mod[i] < 0) {
// 连续2个反引号表明存在冲突,强制把前一个设为正引号 //连续2个反引号表明存在冲突,强制把前一个设为正引号
if (!opend) { if (!opend) {
if (i > 0) mod[i] = 3 if (i > 0) mod[i] = 3
} }
@ -280,7 +292,7 @@ object ContentHelp {
// 修正,断尾必须封闭引号 // 修正,断尾必须封闭引号
if (opend) { if (opend) {
if (arrayQuote[size - 1] - string.length > -3) { if (arrayQuote[size - 1] - string.length > -3) {
// if((match(MARK_QUOTATION,string.charAt(string.length()-1)) || match(MARK_QUOTATION,string.charAt(string.length()-2)))){ //if((match(MARK_QUOTATION,string.charAt(string.length()-1)) || match(MARK_QUOTATION,string.charAt(string.length()-2)))){
if (size > 1) mod[size - 2] = 4 if (size > 1) mod[size - 2] = 4
// 0<=i<size,故无需判断size>=1 // 0<=i<size,故无需判断size>=1
mod[size - 1] = -4 mod[size - 1] = -4
@ -318,9 +330,39 @@ object ContentHelp {
} }
} }
// 第3次循环,匹配并插入换行。 //第3次循环,匹配并插入换行。
// "xxxx" xxxx。\n xxx“xxxx” //"xxxx" xxxx。\n xxx“xxxx”
// 未实现 //未实现
// 使用字典验证ins_n , 避免插入不必要的换行。
// 由于目前没有插入、的列表,无法解决 “xx”、“xx”“xx” 被插入换行的问题
val insN1 = ArrayList<Int>()
for (i in insN) {
if (match("\"'”“", string[i])) {
val start: Int = seekLast(
str,
"\"'”“",
i - 1,
i - WORD_MAX_LENGTH
)
if (start > 0) {
val word = str.substring(start + 1, i)
if (dict.contains(word)) {
//System.out.println("使用字典验证 跳过\tins_n=" + i + " word=" + word);
//引号内如果是字典词条,后方不插入换行符(前方不需要优化)
continue
} else {
//System.out.println("使用字典验证 插入\tins_n=" + i + " word=" + word);
if (match("的地得", str[start])) {
//xx的“xx”,后方不插入换行符(前方不需要优化)
continue
}
}
}
}
insN1.add(i)
}
insN = insN1
// 随机在句末插入换行符 // 随机在句末插入换行符
insN = ArrayList(HashSet(insN)) insN = ArrayList(HashSet(insN))
@ -471,6 +513,34 @@ object ContentHelp {
return buffer.toString() return buffer.toString()
} }
/**
* 从字符串提取引号包围,且不止出现一次的内容为字典
*
* @param str
* @return 词条列表
*/
private fun makeDict(str: String): List<String> {
// 引号中间不包含任何标点
val patten = Pattern.compile(
"""
(?<=["'”“])([^
\p{P}]{1,${WORD_MAX_LENGTH}})(?=["'”“])
""".trimIndent()
)
//Pattern patten = Pattern.compile("(?<=[\"'”“])([^\n\"'”“]{1,16})(?=[\"'”“])");
val matcher = patten.matcher(str)
val cache: MutableList<String> = ArrayList()
val dict: MutableList<String> = ArrayList()
while (matcher.find()) {
val word = matcher.group()
if (cache.contains(word)) {
if (!dict.contains(word)) dict.add(word)
} else cache.add(word)
}
return dict
}
/** /**
* 计算匹配到字典的每个字符的位置 * 计算匹配到字典的每个字符的位置
* *
@ -510,14 +580,14 @@ object ContentHelp {
* *
* @param str 数据字符串 * @param str 数据字符串
* @param key 字典字符串 * @param key 字典字符串
* @param from 从哪个字符开始匹配默认0 * @param from 从哪个字符开始匹配默认最末位
* @param to 匹配到哪个字符不包含此字符默认匹配到最末位 * @param to 匹配到哪个字符不包含此字符默认0
* @return 位置正向计算) * @return 位置正向计算)
*/ */
private fun seekLast(str: String, key: String, from: Int, to: Int): Int { private fun seekLast(str: String, key: String, from: Int, to: Int): Int {
if (str.length - from < 1) return -1 if (str.length - from < 1) return -1
var i = 0 var i = str.lastIndex
if (from > i) i = from if (from < i && i > 0) i = from
var t = 0 var t = 0
if (to > 0) t = to if (to > 0) t = to
var c: Char var c: Char
@ -619,6 +689,9 @@ object ContentHelp {
private const val MARK_QUOTATION = "\"“”" private const val MARK_QUOTATION = "\"“”"
private val PARAGRAPH_DIAGLOG = "^[\"”“][^\"”“]+[\"”“]$".toRegex() private val PARAGRAPH_DIAGLOG = "^[\"”“][^\"”“]+[\"”“]$".toRegex()
// 限制字典的长度
private const val WORD_MAX_LENGTH = 16
private fun match(rule: String, chr: Char): Boolean { private fun match(rule: String, chr: Char): Boolean {
return rule.indexOf(chr) != -1 return rule.indexOf(chr) != -1
} }

Loading…
Cancel
Save