functions1.goΒΆ

// functions1.go

// To run at the command line:
//    $ go run functions1.go

package main

import "fmt"

// returns the first index i such that match(s[i]) is false
// if no character matches, then len(s) is returned
func firstNonMatching(s string, match func(rune) bool) int {
    i := 0
    for i < len(s) && match(rune(s[i])) {
        i++
    }
    return i
}

func getLongestPrefix(s string, match func(rune) bool) string {
    return s[:firstNonMatching(s, match)]
}

func removeLongestPrefix(s string, match func(rune) bool) string {
    return s[firstNonMatching(s, match):]
}

func test_getLongestPrefix() {
    // This is an example of table-driven testing.
    // All the test cases are put in a slice of structs called testcases.
    // Each entry in testcases stores the input and expected output.
    // The code after the table then calls the function being tested, in
    // this case getLongestPrefix, on each entry in test cases, check that
    // the the expected output matches the actual output.
    //
    // Table-driven testing has a couple of nice features. It's automated, so
    // you can easily run it after any change to your code. It's also easy to
    // add new entires to testcases.

    testcases := []struct {
        str      string
        matchFn  func(rune) bool
        expected string
    }{
        {"x+y", isLetter, "x"},
        {"13 * j", isLetter, ""},
        {"13 * j", isDigit, "13"},
        {"one two three", isLetter, "one"},
    }

    failures := 0
    for i, test := range testcases {
        if actual := getLongestPrefix(test.str, test.matchFn); actual != test.expected {
            fmt.Printf("test %v failed:\n", i)
            fmt.Printf("      input: \"%v\"\n", test.str)
            fmt.Printf("     actual: \"%v\"\n", actual)
            fmt.Printf("   expected: \"%v\"\n\n", test.expected)
            failures++
        }
    }
    if failures == 0 {
        fmt.Println("all tests passed")
    } else if failures == 1 {
        fmt.Println("1 test case failed")
    } else {
        fmt.Printf("%v test cases failed\n", failures)
    }
} // test_getLongestPrefix

func main() {
    test_getLongestPrefix()
}

//
// some character matching functions
//

func isWhitespace(r rune) bool {
    return r == ' ' || r == '\n' || r == '\t'
}

func isLower(r rune) bool {
    return 'a' <= r && r <= 'z'
}

func isUpper(r rune) bool {
    return 'A' <= r && r <= 'Z'
}

func isLetter(r rune) bool {
    return isLower(r) || isUpper(r)
}

func isIdentStartChar(r rune) bool {
    return r == '_' || isLetter(r)
}

func isDigit(r rune) bool {
    return '0' <= r && r <= '9'
}

func isIdentChar(r rune) bool {
    return isIdentStartChar(r) || isDigit(r)
}