Go语言:如何检查一个字符串是否包含多个子字符串?

11

strings.Contains(str_to_check, substr) 只接受一个子字符串作为检查对象,如果不想重复使用strings.Contains(),如何检查多个子字符串?

例如:strings.Contains(str_to_check, substr1, substr2)

5个回答

16

您可以使用 strings.Contains() 编写自己的实用函数,以便适用于多个子字符串。

以下是一个示例,它返回布尔值(true/false),以表明是否完全/部分匹配,以及匹配的总数:

package main

import (
    "fmt"
    "strings"
)

func checkSubstrings(str string, subs ...string) (bool, int) {

    matches := 0
    isCompleteMatch := true

    fmt.Printf("String: \"%s\", Substrings: %s\n", str, subs)

    for _, sub := range subs {
        if strings.Contains(str, sub) {
            matches += 1
        } else {
            isCompleteMatch = false
        }
    }

    return isCompleteMatch, matches
}

func main() {
    isCompleteMatch1, matches1 := checkSubstrings("Hello abc, xyz, abc", "abc", "xyz")
    fmt.Printf("Test 1: { isCompleteMatch: %t, Matches: %d }\n", isCompleteMatch1, matches1)

    fmt.Println()

    isCompleteMatch2, matches2 := checkSubstrings("Hello abc, abc", "abc", "xyz")
    fmt.Printf("Test 2: { isCompleteMatch: %t, Matches: %d }\n", isCompleteMatch2, matches2)
}

输出:

String: "Hello abc, xyz, abc", Substrings: [abc xyz]
Test 1: { isCompleteMatch: true, Matches: 2 }

String: "Hello abc, abc", Substrings: [abc xyz]
Test 2: { isCompleteMatch: false, Matches: 1 }

以下是实时示例:https://play.golang.org/p/Xka0KfBrRD


1
好的回答,还有至少两个选项可以使用正则表达式和自定义扫描器 - 请看我的回答。 - Alexander Trakhimenok

16

是的,您可以在不多次调用strings.Contains()的情况下完成此操作。

如果您事先知道子字符串,则使用正则表达式检查最简单。如果要检查的字符串很长,并且有相当多的子字符串,则比多次调用strings.Contains更快。

示例https://play.golang.org/p/7PokxbOOo7

package main

import (
    "fmt"
    "regexp"
)

var re = regexp.MustCompile(`first|second|third`)

func main() {
    fmt.Println(re.MatchString("This is the first example"))
    fmt.Println(re.MatchString("This is the second example after first"))
    fmt.Println(re.MatchString("This is the third example"))
    fmt.Println(re.MatchString("This is the forth example"))
}

输出:

true
true
true
false

如果要检查的子串是动态的,创建正则表达式可能会更加困难,因为需要转义特殊字符,并且正则编译速度不快,所以在这种情况下使用 strings.Contains() 可能更好,虽然最好测试一下你的代码是否对性能至关重要。
另一个很好的选择可能是编写自己的扫描器,可以利用子字符串中的公共前缀(如果有的话)使用 prefix tree

不错,Alex!我们能否使用正则表达式来强制检查所有子字符串? - Azeem
2
如果它们是按特定顺序排列的,那么你可以。如果它们是任意顺序的,你仍然可以,但是正则表达式可能会变得非常复杂,因为对于N > 2,你需要所有可能选项的排列 - 很快就会变得混乱。 - Alexander Trakhimenok
很棒的建议! - CodeGuru

4
另一个解决方案是使用regexpsuffixarray的组合。来自文档的说明如下:

包suffixarray使用内存后缀数组以对数时间实现子字符串搜索。

package main

import (
    "fmt"
    "index/suffixarray"
    "regexp"
    "strings"
)

func main() {
    fmt.Println(contains("first secondthird", "first", "second", "third"))
    fmt.Println(contains("first secondthird", "first", "10th"))
}

func contains(str string, subStrs ...string) bool {
    if len(subStrs) == 0 {
        return true
    }
    r := regexp.MustCompile(strings.Join(subStrs, "|"))
    index := suffixarray.New([]byte(str))
    res := index.FindAllIndex(r, -1)
    exists := make(map[string]int)
    for _, v := range subStrs {
        exists[v] = 1
    }
    for _, pair := range res {
        s := str[pair[0]:pair[1]]
        exists[s] = exists[s] + 1
    }
    for _, v := range exists {
        if v == 1 {
            return false
        }
    }
    return true
}

(在Go Playground中)


0
package main

import (
    "fmt"
    "strings"
)

func main() {
    listStrings := []string{"d", "x"}
    for _,value:= range listStrings {
        if strings.Contains("mystring", value) {
            fmt.Println("Contains")
            break
        }
    }
}

-2
“我怎样在不重复使用strings.Contains()的情况下检查多个子字符串?”
“根本不可能。你必须重复调用Contains。”

注意,我只是想知道是否可以使用更少的代码来实现这个(在Go中)。 - jm33_m0
编写一个实用函数来执行这个操作,然后通过调用这个实用函数,可以用“更少”的代码来完成它。@jm33_m0 - icza
@Volker,不需要。还有其他几个选项-请看我的回答。 - Alexander Trakhimenok
@AlexanderTrakhimenok 当然可以。在任何问题上使用正则表达式都是一个好的解决方案。 - Volker
2
@Volker,没有任何问题。但在某些情况下,编码可能更容易且性能更好。所以我不理解你的讽刺。 - Alexander Trakhimenok

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