测试字符串是否包含字符串数组中的任何内容(Kotlin)

29

我刚接触Kotlin(我有Java背景),但似乎无法弄清如何检查字符串是否包含关键字列表中的匹配项。

我的目标是检查字符串是否包含来自关键字数组的匹配项(忽略大小写)。如果是这样,请打印出与关键字匹配的关键字和包含该关键字的字符串。(我将循环遍历文件中的一堆字符串)。

这是一个MVE:

val keywords = arrayOf("foo", "bar", "spam")

fun search(content: String) {
    var match = <return an array of the keywords that content contained>
    if(match.size > 0) {
          println("Found match(es): " + match + "\n" + content)
    }
}   

fun main(args: Array<String>) {
    var str = "I found food in the barn"
    search(str) //should print out that foo and bar were a match
}

作为一个开始(这忽略了“match”变量和获取匹配关键字列表),我尝试使用以下if语句,根据我在这个问题中找到的内容进行调整。
if(Arrays.stream(keywords).parallel().anyMatch(content::contains))

但它在“content”下面放了一条波浪线,并给了我这个错误:

无法使用提供的参数调用以下任何函数:public operator fun CharSequence.contains(char: Char, ignoreCase: Boolean = ...): Boolean defined in kotlin.text public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = ...): Boolean defined in kotlin.text @InlineOnly public inline operator fun CharSequence.contains(regex: Regex): Boolean defined in kotlin.text

4个回答

39
你可以使用filter函数来仅保留content中包含的关键字。
val match = keywords.filter { it in content }

这里的match是一个List<String>。如果你想要在结果中得到一个数组,你可以添加.toTypedArray()调用。

表达式it in content中的in运算符与content.contains(it)相同。

如果你想要进行大小写不敏感的匹配,你需要在调用contains时指定ignoreCase参数:

val match = keywords.filter { content.contains(it, ignoreCase = true) }

看起来很不错,但还有一个问题:我如何将搜索更改为仅返回关键字是否在内容中找到的布尔函数?是否有简单的一行代码解决方案? - takanuva15
16
将“filter”替换为“any”。 - Marko Topolnik

4

另一个明显的选择是使用正则表达式进行大小写不敏感的匹配:

arrayOf("foo", "bar", "spam").joinToString(prefix = "(?i)", separator = "|").toRegex())

将一个带有前缀内联(?i)不区分大小写修改器的模式与关键字之间的交替粘合在一起:(?i)foo|bar|spam

示例代码:

private val keywords = arrayOf("foo", "bar", "spam")
private val pattern = keywords.joinToString(prefix = "(?i)", separator = "|")
private val rx = pattern.toRegex()

fun findKeyword(content: String): ArrayList<String> { 
    var result = ArrayList<String>()
    rx.findAll(content).forEach { result.add(it.value) }
    return result
}

fun main(args: Array<String>) { 
    println(findKeyword("Some spam and a lot of bar"));
}

正则表达式方法在需要更加复杂的匹配时非常有用,例如添加单词边界\b,或者需要非重叠匹配等情况。

我该如何修改它以仅匹配整个关键词?(例如,如果我的关键词是“foo”,我只想匹配句子中的单词“foo”,而不是“food”) - takanuva15
@takanuva15 keywords.joinToString(prefix = "(?i)\\b", separator = "\\b|\\b", postfix = "\\b") - wp78de

3

以下是我不使用Stream的方法:

fun String.containsAnyOfIgnoreCase(keywords: List<String>): Boolean {
    for (keyword in keywords) {
        if (this.contains(keyword, true)) return true
    }
    return false
}

使用方法:

"test string".containsAnyOfIgnoreCase(listOf("abc","test"))

1
为什么要重复造轮子? - Somaiah Kumbera

2
我认为 Any 是一种高效的方式。
fun findMatch(s: String, strings: List<String>): Boolean {
    return strings.any { s.contains(it) }
}
 
fun main() {
    val today = "Wednesday"
    val weekend = listOf("Sat", "Sun")
    println(if (findMatch(today, weekend)) "Yes" else "No") // No
}

参考:点击此处

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接