我一直在使用SearchView
来筛选RecyclerView
中的项目,但我只是验证包含我筛选的字符串值的字符串。我想要的是能够验证字符串,即使有一些拼写错误和1/2个字母不正确(例如,如果我写了"地狱世界"而不是"你好世界",我仍然希望"你好世界》字符串有效)。
我已经搜索了一段时间如何做到这一点,我发现的唯一一件事是对字符串使用语音匹配,然后使用它进行过滤,但我找不到如何在Kotlin中实现它,我只看到它在PHP中使用,我甚至不认为它真的能满足我的要求。
我很难用语言表达我的需求,所以我希望这是清楚的。
我当前的过滤器采用字符串列表,并根据搜索值是否包含在这些字符串中进行过滤,如下所示:
val filteredList = ArrayList<ShowModel>()
for(str in stringsList) {
if(str.lowercase().contains(filterPattern)) {
filteredList.add(str)
}
}
我应该如何构建一个不太挑剔的搜索过滤器?
(这有点长,但我基本上是在谈论为什么这是一个复杂的问题-有一些实际的解决方案可以在最后使用!)
问题是,计算机是精确的,像过滤器这样的功能是基于满足非常特定的条件。它们不具有模糊性,所以如果你想这样做,你就必须在自己身上对这种行为进行编码(除非你想训练一个神经网络,直到它看起来像是在做你想做的事,但那是另一回事)
因此,你需要精确地确定你想要什么,这样你就可以编写做特定事情的代码。你提到了三件事,但只是含糊地说:
- 处理";错误点击">
- 让1/2的字符是"1";不正确的">
- 语音匹配
对你这个人来说,这些事情可能在直觉上很简单——你知道什么是";错误点击";是的,你知道单词(或单词片段)听起来像什么,以及它们如何与其他单词混淆,你就知道一半的字母是"意味着什么;错误";。计算机不知道这些事情,所以你需要告诉它如何处理这些场景,以及它需要做什么来正确识别匹配。这不是一件简单的事情!
让我们把";一半错误";实例即使从一开始,你和我可能对这到底意味着什么有不同的想法——我们谈论的是50%的角色可能完全不同吗?一对交换的字母是否应该与一对随机字母一样错误,即cmopuetr与cvzpuqr一样错误?对于计算机,你将如何对这两个单词进行评分?你会采取哪些具体步骤来做到这一点?
部分匹配如何,因为末尾缺少字母?计划是否应该与平面比侧翼更匹配?我觉得应该是这样!但所有这些细节使得比较更加困难。如果它是一个简单的";错误字符计数";你可以做一些(天真的)事情,比如
fun String.scoreMatch(other: String) =
zip(other).count { it.first == it.second } / maxOf(length, other.length).toFloat()
以获得较长单词中正确位置的字符百分比,但即使这样也有利于平面而非侧面(由于额外的长度,80%与75%>),并且它不适用于例如开头缺失的字母(每个字符都会移位,因此"错误",类似于交换字符的问题)。看看这是如何快速变得复杂的?这是在我们开始考虑效率或任何事情之前!
我并不是告诉你不要这样做,只是想让你了解问题的规模,以及问题空间实际上有多模糊(这本身就让问题很难解决,因为你不知道自己需要做什么!)但如果你可以放松你的要求,你可以使用一堆现成的解决方案。
有一些常见的算法,比如计算Levenstein距离,这将为提供某种形式的模糊匹配-这可能是一个很好的解决方案,因为它不会完成所有你提到的事情,但它会给你一些智能查找,也许这就足够了!
这里有一个博客,解释了一些模糊匹配算法,包括一个语音算法,如果你真的想要的话,你可以研究一下。博客试图向你出售他们自己的人工智能匹配解决方案,但它给了你一些需要研究的东西!
Levenstein算法是你可以自己实现的,如果你愿意的话,或者会有很多库来实现它——也许有一个很好的快速算法。或者,如果你很乐意使用Apache Commons库,他们有一个text.similarity
包,里面有一堆不同的距离和评分算法,你可以使用。不过,可能会有一个专门的、更专注的图书馆——看看周围吧!这是我看到的一个Python库的Java端口。
请记住,这可能是一个繁重的处理过程,这取决于你必须检查多少字符串,所以你可能想在搜索中实现某种速率限制器-延迟搜索,如果用户继续键入,则重置延迟,诸如此类的事情