feat: 完成优化器设计
This commit is contained in:
@@ -5,6 +5,14 @@ data class PageResponse<E>(
|
||||
val total: Long,
|
||||
)
|
||||
|
||||
data class MapResponse(
|
||||
val data: Map<String, Any>,
|
||||
)
|
||||
|
||||
data class ListResponse(
|
||||
val data: List<Any>
|
||||
)
|
||||
|
||||
data class SingleResponse<E>(
|
||||
val data: Map<String, E>,
|
||||
) {
|
||||
|
||||
103
src/main/kotlin/com/lanyuanxiaoyao/bookstore/Optimization.kt
Normal file
103
src/main/kotlin/com/lanyuanxiaoyao/bookstore/Optimization.kt
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.lanyuanxiaoyao.bookstore
|
||||
|
||||
import cn.hutool.core.convert.Convert
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.LIST
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.MAP
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.NONE
|
||||
|
||||
// @Configuration
|
||||
// class ProcessorConfiguration {
|
||||
// @Bean
|
||||
// fun processors(): Map<String, Processor> = listOf(
|
||||
// CharWidthProcessor()
|
||||
// ).associateBy { it.javaClass.name }
|
||||
// }
|
||||
|
||||
interface Optimization {
|
||||
companion object {
|
||||
fun process(root: JsonNode, optimizationMap: Map<String, Optimization>): List<String> {
|
||||
val text = root.get("text").asText()
|
||||
val nodes = root.get("optimizations") ?: emptyList()
|
||||
var lines = listOf(text)
|
||||
for (node in nodes) {
|
||||
val type = node.get("type").asText()
|
||||
val optimization = optimizationMap[type] ?: throw IllegalArgumentException("Unknown optimization type: $type")
|
||||
lines = when (optimization.argumentType()) {
|
||||
NONE -> optimization.handle(lines, Unit)
|
||||
LIST -> optimization.handle(lines, node.get("argument").map { it.asText() })
|
||||
MAP -> optimization.handle(lines,
|
||||
node
|
||||
.get("argument")
|
||||
.fields()
|
||||
.asSequence()
|
||||
.map { (k, v) -> k to v.asText() }
|
||||
.toMap()
|
||||
)
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
}
|
||||
|
||||
enum class ArgumentType {
|
||||
NONE, LIST, MAP
|
||||
}
|
||||
|
||||
fun key(): String
|
||||
fun name(): String
|
||||
fun handle(line: List<String>, argument: Any): List<String>
|
||||
fun argumentType(): ArgumentType
|
||||
}
|
||||
|
||||
class SliceOptimization() : Optimization {
|
||||
override fun key(): String = "slice-${argumentType()}"
|
||||
|
||||
override fun name(): String = "切分"
|
||||
|
||||
override fun handle(line: List<String>, argument: Any): List<String> {
|
||||
val keys = argument as List<String>
|
||||
var result = line
|
||||
for (key in keys) {
|
||||
result = result.flatMap { it.split(key) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun argumentType(): Optimization.ArgumentType = Optimization.ArgumentType.LIST
|
||||
}
|
||||
|
||||
abstract class AbstractOptimization(private val key: String, private val name: String) : Optimization {
|
||||
override fun key(): String = "${key}-${argumentType()}"
|
||||
override fun name(): String = name
|
||||
|
||||
override fun handle(line: List<String>, argument: Any): List<String> {
|
||||
return line.map { handle(it, argument) }
|
||||
}
|
||||
|
||||
override fun argumentType(): Optimization.ArgumentType = Optimization.ArgumentType.NONE
|
||||
|
||||
abstract fun handle(line: String, argument: Any): String
|
||||
}
|
||||
|
||||
class TrimOptimization : AbstractOptimization("trim", "移除前后空白") {
|
||||
override fun handle(line: String, argument: Any): String {
|
||||
if (line.isBlank()) return line
|
||||
return line.trim()
|
||||
}
|
||||
}
|
||||
|
||||
class CharWidthOptimization : AbstractOptimization("char-width", "半角字符转全角字符") {
|
||||
override fun handle(line: String, argument: Any): String {
|
||||
if (line.isBlank()) return line
|
||||
return Convert
|
||||
.toDBC(line)
|
||||
.replace(",", ",")
|
||||
.replace("?", "?")
|
||||
.replace("!", "!")
|
||||
.replace(";", ";")
|
||||
.replace(":", ":")
|
||||
.replace("(", "(")
|
||||
.replace(")", ")")
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.lanyuanxiaoyao.bookstore
|
||||
|
||||
import cn.hutool.core.convert.Convert
|
||||
|
||||
// @Configuration
|
||||
// class ProcessorConfiguration {
|
||||
// @Bean
|
||||
// fun processors(): Map<String, Processor> = listOf(
|
||||
// CharWidthProcessor()
|
||||
// ).associateBy { it.javaClass.name }
|
||||
// }
|
||||
|
||||
interface Slicer {
|
||||
fun slice(text: String): List<String>
|
||||
}
|
||||
|
||||
open class RegexSlicer(private val regex: Regex) : Slicer {
|
||||
override fun slice(text: String): List<String> {
|
||||
return text.split(regex)
|
||||
}
|
||||
}
|
||||
|
||||
interface Optimization {
|
||||
fun handle(line: String): String
|
||||
}
|
||||
|
||||
class TrimOptimization : Optimization {
|
||||
override fun handle(line: String): String {
|
||||
if (line.isBlank()) return line
|
||||
return line.trim()
|
||||
}
|
||||
}
|
||||
|
||||
class CharWidthOptimization : Optimization {
|
||||
override fun handle(line: String): String {
|
||||
if (line.isBlank()) return line
|
||||
return Convert.toDBC(line)
|
||||
}
|
||||
}
|
||||
|
||||
class QuoteCovertChineseOptimization : Optimization {
|
||||
override fun handle(line: String): String {
|
||||
return line
|
||||
.replace(",", ",")
|
||||
.replace("?", "?")
|
||||
.replace("!", "!")
|
||||
.replace(";", ";")
|
||||
.replace(":", ":")
|
||||
.replace("(", "(")
|
||||
.replace(")", ")")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.lanyuanxiaoyao.bookstore.controller
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.lanyuanxiaoyao.bookstore.CharWidthOptimization
|
||||
import com.lanyuanxiaoyao.bookstore.ListResponse
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.LIST
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.MAP
|
||||
import com.lanyuanxiaoyao.bookstore.Optimization.ArgumentType.NONE
|
||||
import com.lanyuanxiaoyao.bookstore.SingleResponse
|
||||
import com.lanyuanxiaoyao.bookstore.SliceOptimization
|
||||
import com.lanyuanxiaoyao.bookstore.TrimOptimization
|
||||
import java.awt.SystemColor.text
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("optimization")
|
||||
class OptimizationController(builder: Jackson2ObjectMapperBuilder) {
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
private val mapper: ObjectMapper = builder.build()
|
||||
private val optimizations: List<Optimization> = listOf(
|
||||
SliceOptimization(),
|
||||
TrimOptimization(),
|
||||
CharWidthOptimization(),
|
||||
)
|
||||
private val optimizationMap: Map<String, Optimization> = optimizations.associateBy { it.key() }
|
||||
|
||||
@GetMapping("optimizations")
|
||||
fun optimizations(): ListResponse {
|
||||
return ListResponse(optimizations.map { mapOf("value" to it.key(), "label" to it.name()) })
|
||||
}
|
||||
|
||||
@PostMapping("execute")
|
||||
fun execute(@RequestBody json: String): SingleResponse<String> {
|
||||
val root = mapper.readTree(json)
|
||||
val lines = Optimization.process(root, optimizationMap)
|
||||
return SingleResponse(lines.joinToString("\n"))
|
||||
}
|
||||
}
|
||||
@@ -36,3 +36,11 @@ function paginationOption() {
|
||||
total: '${total}'
|
||||
}
|
||||
}
|
||||
|
||||
function arrayInCheck(array, field) {
|
||||
return `\${ARRAYINCLUDES(['${array.join("','")}'], ${field})}`
|
||||
}
|
||||
|
||||
function arrayOutCheck(array, field) {
|
||||
return `\${!ARRAYINCLUDES(['${array.join("','")}'], ${field})}`
|
||||
}
|
||||
|
||||
@@ -27,17 +27,29 @@
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
<script src="sdk/sdk.js"></script>
|
||||
<script>
|
||||
const information = {
|
||||
debug: false,
|
||||
name: '书籍中心',
|
||||
description: '网络书籍精排版工具',
|
||||
base: 'http://127.0.0.1:23890',
|
||||
}
|
||||
</script>
|
||||
<script src="components/helper.js"></script>
|
||||
<script src="components/book.js"></script>
|
||||
<script src="components/chapter.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
let debug = false
|
||||
let amis = amisRequire('amis/embed')
|
||||
let amisJSON = {
|
||||
type: 'page',
|
||||
title: '书籍中心',
|
||||
subTitle: '网络书籍精排版工具',
|
||||
body: {
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
title: '书架',
|
||||
body: [
|
||||
{
|
||||
id: 'book-list',
|
||||
@@ -110,22 +122,115 @@
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '优化',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
name: 'optimization-form',
|
||||
body: [
|
||||
{
|
||||
type: 'textarea',
|
||||
name: 'text',
|
||||
label: '正文',
|
||||
required: true,
|
||||
...formInputClearable(),
|
||||
showCounter: true,
|
||||
trimContents: true,
|
||||
minRows: 5,
|
||||
maxRows: 5,
|
||||
},
|
||||
{
|
||||
type: 'combo',
|
||||
name: 'optimizations',
|
||||
label: '优化器',
|
||||
required: true,
|
||||
multiLine: true,
|
||||
multiple: true,
|
||||
draggable: true,
|
||||
items: [
|
||||
{
|
||||
name: 'type',
|
||||
label: '类型',
|
||||
type: 'select',
|
||||
required: true,
|
||||
selectFirst: true,
|
||||
source: '${base}/optimization/optimizations',
|
||||
},
|
||||
{
|
||||
visibleOn: "${ENDSWITH(type, 'MAP')}",
|
||||
type: 'input-kv',
|
||||
name: 'argument',
|
||||
label: '参数',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
visibleOn: "${ENDSWITH(type, 'LIST')}",
|
||||
type: 'combo',
|
||||
name: 'argument',
|
||||
label: '参数',
|
||||
required: true,
|
||||
multiple: true,
|
||||
multiLine: true,
|
||||
flat: true,
|
||||
items: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'argument',
|
||||
label: '目标值',
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'action',
|
||||
label: '执行优化',
|
||||
className: 'w-full mb-5',
|
||||
level: 'primary',
|
||||
actionType: 'ajax',
|
||||
api: {
|
||||
method: 'post',
|
||||
url: '${base}/optimization/execute',
|
||||
data: {
|
||||
text: '${text|default:undefined}',
|
||||
optimizations: '${optimizations|default:undefined}'
|
||||
}
|
||||
},
|
||||
reload: 'optimization-form?newText=${item}'
|
||||
},
|
||||
{
|
||||
disabled: true,
|
||||
type: 'diff-editor',
|
||||
name: 'newText',
|
||||
label: '正文优化',
|
||||
diffValue: '${text}',
|
||||
language: 'plain-text'
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
amis.embed(
|
||||
'#root',
|
||||
amisJSON,
|
||||
{
|
||||
data: {
|
||||
base: 'http://127.0.0.1:23890',
|
||||
...information
|
||||
},
|
||||
},
|
||||
{
|
||||
theme: 'antd',
|
||||
enableAMISDebug: debug,
|
||||
enableAMISDebug: information.debug,
|
||||
},
|
||||
);
|
||||
if (debug) {
|
||||
if (information.debug) {
|
||||
console.log('Source', amisJSON)
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -9,11 +9,10 @@ class ChapterOptimization {
|
||||
val optimizations = listOf(
|
||||
TrimOptimization(),
|
||||
CharWidthOptimization(),
|
||||
QuoteCovertChineseOptimization(),
|
||||
)
|
||||
val content = File("C:\\Users\\lanyuanxiaoyao\\Downloads\\第141章-反攻云岚宗.txt")
|
||||
.readLines()
|
||||
.joinToString("\n") { optimizations.fold(it) { line, optimization -> optimization.handle(line) } }
|
||||
.joinToString("\n") { optimizations.fold(it) { line, optimization -> optimization.handle(line, optimization.argumentType()) } }
|
||||
println(content)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user