Fix fuzzyCompare

This commit is contained in:
Him188 2020-08-22 21:49:09 +08:00
parent faaf8d34f2
commit cdc9f8f613
2 changed files with 37 additions and 40 deletions

View File

@ -195,12 +195,15 @@ public object ExistMemberArgumentParser : InternalCommandArgumentParserExtension
- `botId.group.memberId` - `botId.group.memberId`
- `botId.group.memberCard` (模糊搜索, 寻找最优匹配) - `botId.group.memberCard` (模糊搜索, 寻找最优匹配)
- `~` (指代指令调用人自己. 仅聊天环境下) - `~` (指代指令调用人自己. 仅聊天环境下)
- `$` (随机成员)
当只登录了一个 [Bot] , 无需上述 `botId` 参数即可 当只登录了一个 [Bot] , 无需上述 `botId` 参数即可
""".trimIndent() """.trimIndent()
public override fun parse(raw: String, sender: CommandSender): Member { public override fun parse(raw: String, sender: CommandSender): Member {
if (raw == "~") return (sender as? MemberCommandSender)?.user ?: illegalArgument("当前语境下无法推断目标群员") if (raw == "~") return (sender as? MemberCommandSender)?.user ?: illegalArgument("当前语境下无法推断自身作为群员")
if (raw == "\$") return (sender as? MemberCommandSender)?.group?.members?.randomOrNull()
?: illegalArgument("当前语境下无法推断随机群员")
val components = raw.split(".") val components = raw.split(".")
@ -221,7 +224,12 @@ public object ExistMemberArgumentParser : InternalCommandArgumentParserExtension
public override fun parse(raw: SingleMessage, sender: CommandSender): Member { public override fun parse(raw: SingleMessage, sender: CommandSender): Member {
return if (raw is At) { return if (raw is At) {
checkArgument(sender is MemberCommandSender) checkArgument(sender is MemberCommandSender)
sender.group.members[raw.target] val bot = sender.inferBotOrFail()
val group = sender.inferGroupOrFail()
if (raw.target == bot.id) {
return group.botAsMember
}
group[raw.target]
} else { } else {
parse(raw.content, sender) parse(raw.content, sender)
} }
@ -247,10 +255,12 @@ internal interface InternalCommandArgumentParserExtensions<T : Any> : CommandArg
fun Bot.findMemberOrFail(id: String): Friend = fun Bot.findMemberOrFail(id: String): Friend =
getFriendOrNull(id.parseToLongOrFail()) ?: illegalArgument("无法找到群员: $this") getFriendOrNull(id.parseToLongOrFail()) ?: illegalArgument("无法找到群员: $this")
fun Group.findMemberOrFail(idOrCard: String): Member = fun Group.findMemberOrFail(idOrCard: String): Member {
idOrCard.toLongOrNull()?.let { getOrNull(it) } if (idOrCard == "\$") return members.randomOrNull() ?: illegalArgument("当前语境下无法推断随机群员")
return idOrCard.toLongOrNull()?.let { getOrNull(it) }
?: fuzzySearchMember(idOrCard) ?: fuzzySearchMember(idOrCard)
?: illegalArgument("无法找到目标群员 $idOrCard") ?: illegalArgument("无法找到目标群员 $idOrCard")
}
fun CommandSender.inferBotOrFail(): Bot = (this as? BotAwareCommandSender)?.bot ?: illegalArgument("当前语境下无法推断目标群员") fun CommandSender.inferBotOrFail(): Bot = (this as? BotAwareCommandSender)?.bot ?: illegalArgument("当前语境下无法推断目标群员")

View File

@ -14,6 +14,7 @@ import net.mamoe.mirai.console.command.description.CommandArgumentParserExceptio
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.nameCardOrNick import net.mamoe.mirai.contact.nameCardOrNick
import kotlin.math.max
internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean { internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean {
@ -31,53 +32,39 @@ internal infix fun Array<out String>.intersectsIgnoringCase(other: Array<out Str
return false return false
} }
internal fun String.fuzzyCompare(target: String): Double { internal fun String.fuzzyMatchWith(target: String): Double {
var step = 0
if (this == target) { if (this == target) {
return 1.0 return 1.0
} }
if (target.length > this.length) { var match = 0
return 0.0 for (i in 0..(max(this.lastIndex, target.lastIndex))) {
} val t = target.getOrNull(match)
for (i in this.indices) { if (t == this.getOrNull(i) && t != null) {
if (target.length == i) { match++
step--
} else {
if (this[i] != target[i]) {
break
}
step++
} }
} }
return match.toDouble() / (max(this.lastIndex, target.lastIndex) + 1)
if (step == this.length - 1) {
return 1.0
}
return step.toDouble() / this.length
} }
/**
* 模糊搜索一个List中index最接近target的东西
*/
internal inline fun <T : Any> Collection<T>.fuzzySearch( internal inline fun <T : Any> Collection<T>.fuzzySearch(
target: String, target: String,
index: (T) -> String crossinline index: (T) -> String
): T? { ): T? {
var potential: T? = null var maxElement: T? = null
var rate = 0.0 var max = 0.0
this.forEach {
val thisIndex = index(it) for (t in this) {
if (thisIndex == target) { val r = index(t).fuzzyMatchWith(target)
return it if (r > max) {
} maxElement = t
with(thisIndex.fuzzyCompare(target)) { max = r
if (this > rate) {
rate = this
potential = it
}
} }
} }
return potential
if (max >= 0.7) {
return maxElement
}
return null
} }
/** /**
@ -93,7 +80,7 @@ internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
var rate = 0.0 var rate = 0.0
var collide = 0 var collide = 0
this.forEach { this.forEach {
with(index(it).fuzzyCompare(target)) { with(index(it).fuzzyMatchWith(target)) {
if (this > rate) { if (this > rate) {
rate = this rate = this
potential = it potential = it