如何检查字符串中的一个或多个符号

问题描述:

I'm struggling to find a method of checking to see if a string contains one or more symbols like the following: #}{&*"(£) While it's fairly trivial to make a check for one or more of these symbols I'm not looking to build and maintain a list or dictionary of possible entries. Is there a way I can check to see if a string contains one or more of any non standard symbol in go preferably using the standard library?

Specifically I'm looking to detect anything that isn't a-zA-Z0-9 which for the basis of my question would be counted as a non standard symbol.

In Go, write a simple function. For example,

package main

import (
    "fmt"
)

func isStandard(s string) bool {
    for i := 0; i < len(s); i++ {
        switch b := s[i]; {
        case b >= 'a' && b <= 'z':
            continue
        case b >= 'A' && b <= 'Z':
            continue
        case b >= '0' && b <= '9':
            continue
        default:
            return false
        }
    }
    return true
}

func main() {
    fmt.Println(isStandard(`ABCabc123`))
    fmt.Println(isStandard(`#}{&*"(£)`))
}

Playground: https://play.golang.org/p/Y2KjDcHSupH

Output:

true
false

The Go Programming Language Specification

Switch statements

"Switch" statements provide multi-way execution. An expression or type specifier is compared to the "cases" inside the "switch" to determine which branch to execute.

Expression switches

In an expression switch, the switch expression is evaluated and the case expressions, which need not be constants, are evaluated left-to-right and top-to-bottom; the first one that equals the switch expression triggers execution of the statements of the associated case; the other cases are skipped. If no case matches and there is a "default" case, its statements are executed. There can be at most one default case and it may appear anywhere in the "switch" statement.

The switch expression may be preceded by a simple statement, which executes before the expression is evaluated.

Fallthrough statements

A "fallthrough" statement transfers control to the first statement of the next case clause in an expression "switch" statement. It may be used only as the final non-empty statement in such a clause.


switch b := s[i]; {
    // ...
}

is equivalent to

switch b := s[i]; true {
    // ...
}

is equivalent to

{
    b := s[i]
    switch true {
        // ...
    } 
}

The simple statement b := s[i] declares b to be a switch { } statement block local variable.

The case expresions are evaluated and compared to true. If none are true, the default is taken.

Go, unlike C, requires explicit fallthrough.

ASCII is a subset of Unicode UTF-8. Since the standard characters are all ASCII, we can simply compare bytes.


Here is a simple benchmark.

Output:

$ go test standard_test.go -bench=. -benchmem
BenchmarkPeterSO-8    200000000       8.10 ns/op    0 B/op    0 allocs/op
BenchmarkJubobs-8      10000000     222 ns/op       0 B/op    0 allocs/op
$ 

standard_test.go:

package main

import (
    "regexp"
    "testing"
)

func isStandard(s string) bool {
    for i := 0; i < len(s); i++ {
        switch b := s[i]; {
        case b >= 'a' && b <= 'z':
            continue
        case b >= 'A' && b <= 'Z':
            continue
        case b >= '0' && b <= '9':
            continue
        default:
            return false
        }
    }
    return true
}

func BenchmarkPeterSO(b *testing.B) {
    std := `ABCabc123`
    for N := 0; N < b.N; N++ {
        isStandard(std)
    }
}

var (
    whitelist  = "A-Za-z0-9"
    disallowed = regexp.MustCompile("[^" + whitelist + " ]+")
)

func IsValid(s string) bool {
    return !disallowed.MatchString(s)
}

func BenchmarkJubobs(b *testing.B) {
    std := `ABCabc123`
    for N := 0; N < b.N; N++ {
        IsValid(std)
    }
}

Since the whitelist can easily be defined as a regexp, use regexp.MatchString:

package main

import (
    "fmt"
    "regexp"
)

var (
    whitelist  = "A-Za-z0-9"
    disallowed = regexp.MustCompile(fmt.Sprintf("[^%s]+", whitelist))
)

func main() {
    fmt.Println(IsValid("foobar007"))
    fmt.Println(IsValid("foo%bar&007"))
}

func IsValid(s string) bool {
    return !disallowed.MatchString(s)
}

(playground)