12

strings.Contains(str_to_check, substr) takes only one argument as the substring to check, how do I check multiple substrings without using strings.Contains() repeatedly?

eg. strings.Contains(str_to_check, substr1, substr2)

0

5 Answers 5

19

Yes, you can do this without calling strings.Contains() multiple times.

If you know substrings in advance the easiest way to check this with regular expression. And if a string to check is long and you have quite a few substrings it can be more fast then calling multiple strings.Contains

Example 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"))
}

Output:

true
true
true
false

If the subs to check are dynamic it may be a bit more difficult to create regex as you need to escape special characters and regex compilation is not fast so strings.Contains() may be better in this case though it's better test if your code is performance critical.

Another good option could be to write your own scanner that can leverage common prefixes in substrings (if any) using prefix tree.

Sign up to request clarification or add additional context in comments.

3 Comments

Nice one, Alex! Can we impose the checking of all the sub-strings using regex?
You can if they are in specific order. If they are in arbitrary order you still can but the regex could become pretty complicated for N > 2 as you would need permutation of all possible options - will become messy pretty quickly.
Great Suggestion!
17

You can write your own utility function using strings.Contains() that can work for multiple sub-strings.

Here's an example that returns Boolean (true/false) in case of complete / partial match and the total number of matches:

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)
}

Output:

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 }

Here's the live example: https://play.golang.org/p/Xka0KfBrRD

1 Comment

Good answer, there is also at least 2 other options with using regex and custom scanner - see my answer.
5

Another solution would be using a combination of regexp and suffixarray. From the documentation:

Package suffixarray implements substring search in logarithmic time using an in-memory suffix array.

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
}

(In Go Playground)

Comments

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
        }
    }
}

Comments

-2

[H]ow do I check multiple substrings without using strings.Contains() repeatedly?

Not at all. You have to call Contains repeatedly.

5 Comments

noted, i was just wondering if i can use less code to achieve this (in Go)
@jm33_m0 Write a util function doing just this, and from there on you can do it with "less" code by calling this util function.
@Volker, no you have not to. There are few other options - see my answer.
@AlexanderTrakhimenok Of course. Throwing regexps at any problem is a fine solution.
@Volker, not at any problem. But in some cases it can be easier to code and have better performance. So I'm not getting your sarcasm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.