Repository: VerbalExpressions/GoVerbalExpressions Branch: master Commit: 4d76a1099a6e Files: 8 Total size: 28.3 KB Directory structure: gitextract_ib90aowl/ ├── .gitignore ├── LICENSE ├── README.md ├── doc.go ├── example_test.go ├── helpers.go ├── verbalexpressions.go └── verbalexpressions_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.swp ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Patrice FERLET (metal3d.org) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ GoVerbalExpressions =================== [![Build Status](https://drone.io/github.com/VerbalExpressions/GoVerbalExpressions/status.png)](https://drone.io/github.com/VerbalExpressions/GoVerbalExpressions/latest) [![Coverage Status](https://coveralls.io/repos/VerbalExpressions/GoVerbalExpressions/badge.png?branch=master)](https://coveralls.io/r/VerbalExpressions/GoVerbalExpressions?branch=master) Go VerbalExpressions implementation VerbalExpression is a concept to help building difficult regular expressions. See online doc here: http://godoc.org/github.com/VerbalExpressions/GoVerbalExpressions ## Other Implementations You can see an up to date list of all ports on [VerbalExpressions.github.io](http://VerbalExpressions.github.io). - [Javascript](https://github.com/jehna/VerbalExpressions) - [Ruby](https://github.com/VerbalExpressions/RubyVerbalExpressions) - [C#](https://github.com/VerbalExpressions/CSharpVerbalExpressions) - [Python](https://github.com/VerbalExpressions/PythonVerbalExpressions) - [Java](https://github.com/VerbalExpressions/JavaVerbalExpressions) - [PHP](https://github.com/VerbalExpressions/PHPVerbalExpressions) - [C++](https://github.com/VerbalExpressions/CppVerbalExpressions) - [Haskell](https://github.com/VerbalExpressions/HaskellVerbalExpressions) ## Installation Use this command line: go get github.com/VerbalExpressions/GoVerbalExpressions This will install package in your $GOPATH and you will be ready to import it. ## Examples ```go // import with a nice name import ( "github.com/VerbalExpressions/GoVerbalExpressions" // imports verbalexpressions package "fmt" ) func main () { v := verbalexpressions.New(). StartOfLine(). Then("http"). Maybe("s"). Then( "://"). Maybe("www."). AnythingBut(" "). EndOfLine() testMe := "https://www.google.com" if v.Test(testMe) { fmt.Println("You have a valid URL") } else { fmt.Println("URL is incorrect") } } ``` We try to give alias method and/or helpers. For example: ```go // s will be "We have a blue house" s := verbalexpressions.New().Find("red").Replace("We have a red house", "blue") // c will be: // [ // ["http://www.google.com", "http://", "www.google.com"] // ] c := verbalexpressions.New(). BeginCapture(). Find("http").Maybe("s").Find("://"). EndCapture(). BeginCapture(). Find("www.").Anything(). EndCapture(). Captures("http://www.google.com") // check c[0][1] => http:// // c[0][2] => www.google.com ``` ================================================ FILE: doc.go ================================================ /* This is a Go implementation of VerbalExpressions for other languages. Check http://VerbalExpressions.github.io to know the other implementations. VerbalExperssions is a way to build complex regular expressions with a verbal language. The repo name is "GoVerbalExpressions" but the real package name is "verbalexpressions". So, to import verbalexpressions package, just do: import "github.com/VerbalExpressions/GoVerbalExpressions" Then, use "verbalexpressions" as prefix. There is a simple example Use "New()" factory then you can chain calls. Go syntax allows you to set new line after seperators: v := verbalexpressions.New(). StartOfLine(). Find("foo"). Word(). Anything(). EndOfLine() Then, you can use "Test()" method to check if your string matches expression. You may get the regexp.Regexp structure using "Regex()" method, then use common methods to split, replace, find submatches and so on... as usual There are some helpers that use direct call to the regexp package: - Replace - Captures - Test */ package verbalexpressions ================================================ FILE: example_test.go ================================================ package verbalexpressions_test import ( "fmt" "github.com/VerbalExpressions/GoVerbalExpressions" ) func ExampleVerbalExpression_Find() { s := "foo bar baz" v := verbalexpressions.New().Find("bar") fmt.Println(v.Test(s)) // Output: true } func ExampleVerbalExpression_Captures() { s := `This should get barsystem and whatever... And there, another barelement to fetch` // get "bar" followed by a word v := verbalexpressions.New().Anything(). BeginCapture(). Find("bar").Word(). EndCapture() res := v.Captures(s) // walk results for _, element := range res { // i reprensent capture count and element is a // slice with captures (0 = global find, 1 = first capture) fmt.Printf("Global capture: %s\n", element[0]) fmt.Printf("First capture: %s\n", element[1]) } //Output: //Global capture: This should get barsystem //First capture: barsystem //Global capture: And there, another barelement //First capture: barelement } func ExampleVerbalExpression_Range() { s := "This 1 is 55 a TEST" v := verbalexpressions.New().Range("a", "z", 0, 9) res := v.Regex().FindAllString(s, -1) fmt.Println(res) //Output: [h i s 1 i s 5 5 a] } func ExampleVerbalExpression_Any() { s := "foo1 foo5 foobar" v := verbalexpressions.New().Find("foo").Any("1234567890").Regex().FindAllString(s, -1) fmt.Println(v) //Output: [foo1 foo5] } func ExampleVerbalExpression_Or() { s := "This is a foo and a bar there" v1 := verbalexpressions.New().Find("bar") v := verbalexpressions.New(). Find("foo"). Or(v1) fmt.Println(v.Regex().FindAllString(s, -1)) //Output: [foo bar] } func ExampleVerbalExpression_Replace() { s := "We've got a red house" res := verbalexpressions.New().Find("red").Replace(s, "blue") fmt.Println(res) //Output: We've got a blue house } func ExampleVerbalExpression_AnythingBut() { s := "This is a simple test" v := verbalexpressions.New().AnythingBut("ie").Regex().FindAllString(s, -1) fmt.Println(v) //Output: [Th s s a s mpl t st] } ================================================ FILE: helpers.go ================================================ package verbalexpressions /* proxy and helpers to regexp.Regexp functions */ // Test return true if verbalexpressions matches something in string "s" func (v *VerbalExpression) Test(s string) bool { return v.Regex().Match([]byte(s)) } // Replace alias to regexp.ReplaceAllString. It replace the found expression from // string src by string dst func (v *VerbalExpression) Replace(src string, dst string) string { return v.Regex().ReplaceAllString(src, dst) } // Returns a slice of results from captures. If you didn't apply BeginCapture() and EndCapture(), the slices // will return slice of []string where []string is length 1, and 0 index is the global capture func (v *VerbalExpression) Captures(s string) [][]string { iter := 1 if v.flags&GLOBAL != 0 { iter = -1 } return v.Regex().FindAllStringSubmatch(s, iter) } ================================================ FILE: verbalexpressions.go ================================================ // Copyright 2013 Patrice FERLET // Use of this source code is governed by MIT-style // license that can be found in the LICENSE file package verbalexpressions import ( "fmt" "log" "regexp" "strconv" "strings" ) type Flag uint const ( MULTILINE Flag = 1 << iota IGNORE_CASE DOTALL UNGREEDY GLOBAL ) // VerbalExpression structure to create expression type VerbalExpression struct { expression string parts []string suffixes string prefixes string flags Flag compiled bool regexp *regexp.Regexp } // quote is an alias to regexp.QuoteMeta func quote(s string) string { return regexp.QuoteMeta(s) } // utility function to return only strings func tostring(i interface{}) string { var r string switch x := i.(type) { case string: r = x case uint64: r = strconv.FormatUint(x, 10) case int64: r = strconv.FormatInt(x, 10) case uint: r = strconv.FormatUint(uint64(x), 10) case int: r = strconv.FormatInt(int64(x), 10) default: log.Panicf("Could not convert %v %t", x, x) } return r } // Instanciate a new VerbalExpression. You should use this method to // initalize some internal var. // // Example: // v := verbalexpression.New().Find("foo") func New() *VerbalExpression { r := new(VerbalExpression) r.flags = MULTILINE | GLOBAL r.parts = make([]string, 0) return r } // append a modifier func (v *VerbalExpression) addmodifier(f Flag) *VerbalExpression { v.compiled = false //reinit previous regexp compilation v.flags |= f return v } // remove a modifier func (v *VerbalExpression) removemodifier(f Flag) *VerbalExpression { v.compiled = false //reinit previous regexp compilation v.flags &= ^f return v } // append modifiers that are activated func (v *VerbalExpression) getFlags() string { flags := "misU" // warning, follow Flag const order result := []rune{} for i, flag := range flags { if v.flags&(1< 2 { panic("Multiple: you can only give 1 or to multipliers, min and max as int") } // fetch multiplier if any var min, max int = -1, -1 mult := "+" if len(mults) > 0 { min = mults[0] if len(mults) == 2 { max = mults[1] } } if min == 0 && max == 1 { // 0 or 1 time mult = "?" } if min == 0 && max == -1 { // 0 or more mult = "*" } if min == 1 && max == -1 { // at least 1 time mult = "+" } if min > 1 && max == -1 { //at least min times mult = fmt.Sprintf("{%d,}", min) } if max > 1 { if min > 0 { // min to max times mult = fmt.Sprintf("{%d,%d}", min, max) } else { // max times mult = fmt.Sprintf("{,%d}", max) } } return v.add("(?:" + quote(s) + ")" + mult) } // Or, chains an alternative VerbalExpression func (v *VerbalExpression) Or(ve *VerbalExpression) *VerbalExpression { v.parts = append(v.parts, ve.Regex().String()+"|") return v } // Add another VerbalExpression to the current. // Usefull to concatenate several complex search patterns func (v *VerbalExpression) And(ve *VerbalExpression) *VerbalExpression { return v.add("(?:" + ve.Regex().String() + ")") } // WithAnyCase asks verbalexpressions to match with or without case sensitivity func (v *VerbalExpression) WithAnyCase(sensitive bool) *VerbalExpression { if sensitive { return v.addmodifier(IGNORE_CASE) } return v.removemodifier(IGNORE_CASE) } // SearchOneLine deactivates "multiline" mode if online argument is true // Default is false func (v *VerbalExpression) SearchOneLine(oneline bool) *VerbalExpression { if !oneline { return v.addmodifier(MULTILINE) } return v.removemodifier(MULTILINE) } // MatchAllWithDot lets VerbalExpression matching "." for everything including \n, \r, and so on func (v *VerbalExpression) MatchAllWithDot(enable bool) *VerbalExpression { if enable { return v.addmodifier(DOTALL) } return v.removemodifier(DOTALL) } // Regex returns the regular expression to use to test on string. func (v *VerbalExpression) Regex() *regexp.Regexp { if !v.compiled { v.regexp = regexp.MustCompile( strings.Join([]string{ strings.Join(v.parts, ""), `(?` + v.getFlags() + `)`, v.prefixes, v.expression, v.suffixes}, "")) v.compiled = true } return v.regexp } func (v *VerbalExpression) StopAtFirst(enable bool) *VerbalExpression { if enable { return v.removemodifier(GLOBAL) } return v.addmodifier(GLOBAL) } /* Already implemented => v v add v startOfLine v endOfLine v then v find v maybe v anything v anythingBut v something v somethingBut v replace v lineBreak v br (shorthand for lineBreak) v tab v word v anyOf v any (shorthand for anyOf) v range v withAnyCase v stopAtFirst v searchOneLine v multiple v or v begindCapture v endCapture */ ================================================ FILE: verbalexpressions_test.go ================================================ // Copyright 2013 Patrice FERLET // Use of this source code is governed by MIT-style // license that can be found in the LICENSE file package verbalexpressions import "testing" import "strings" func assertStringEquals(s1, s2 string, t *testing.T) { if s1 != s2 { t.Errorf("%s != %s", s1, s2) } } func TestChaining(t *testing.T) { exp := "http://www.google.com" v := New().StartOfLine(). Then("http"). Maybe("s"). Then("://"). Maybe("www."). Word(). Then("."). Word(). Maybe("/"). EndOfLine() if !v.Test(exp) { t.Errorf("%v regexp doesn't match %s", v.Regex(), exp) } } func TestRange(t *testing.T) { exp := "abcdef 123" v := New().Range("a", "z", 0, 9) if v.Regex().String() != "(?m)[a-z0-9]" { t.Errorf("%s is not (?m)[a-z0-9]", v.Regex()) } if !v.Test(exp) { t.Errorf("%v regexp doesn't match %s", v.Regex(), exp) } exp = "ABCDEF" if v.Test(exp) { t.Errorf("%v regexp should not match %s", v.Regex(), exp) } } func TestPanicOnRangeOddParams(t *testing.T) { defer func() { // if no panic... the test fails if r := recover(); r == nil { t.Errorf("Call must panic !") } }() New().Range("a", "z", 0, 9, 10) } func TestOneLine(t *testing.T) { s := "atlanta\narkansas\nalabama\narachnophobia" v := New().SearchOneLine(true).Find("a").EndOfLine().Regex() res := v.FindAllStringIndex(s, -1) if len(res) != 1 { t.Errorf("%v should be length 1, %d instead", res, len(res)) } if len(res[0]) != 2 { t.Errorf("%v should be length 2, %d instead", res[0], len(res[0])) } v = New().SearchOneLine(false).Find("a").EndOfLine().Regex() res = v.FindAllStringIndex(s, -1) if len(res) != 3 { t.Errorf("%v should be length 3, %d instead", res, len(res)) } for _, r := range res { if len(r) != 2 { t.Errorf("%v should be length 2, %d instead", r, len(r)) } } } func TestAnythingBut(t *testing.T) { s := "This is a simple test" v := New().AnythingBut("im").Regex().FindAllString(s, -1) for _, st := range v { if strings.Contains(st, "i") { t.Errorf("%s should not find \"i\"", st) } if strings.Contains(st, "m") { t.Errorf("%s should not find \"m\"", st) } } } func TestAny(t *testing.T) { s := "foo1 foo5 foobar" v := New().Find("foo").Any("1234567890") res := v.Regex().FindAllString(s, -1) if len(res) != 2 { t.Errorf("len(res) : %d isn't 2", len(res)) } //test alias v = New().Find("foo").AnyOf("1234567890") res = v.Regex().FindAllString(s, -1) if len(res) != 2 { t.Errorf("len(res) : %d isn't 2", len(res)) } } func TestReplace(t *testing.T) { s := "foomode barmode themodebaz" expect := "foochanged barchanged thechangedbaz" v := New().Find("mode") res := v.Replace(s, "changed") if res != expect { t.Errorf("Replacement hasn't worked as expected %s != %s", res, expect) } } func TestCaptures(t *testing.T) { s := "this is a foobarsystem to get bar" v := New().Anything().Find("foo").Find("bar").Word() res := v.Regex().FindAllStringSubmatch(s, -1) if len(res[0]) > 1 { t.Errorf("%v is not a slice of only one match (globale match)", res) } if res[0][0] != "this is a foobarsystem" { t.Errorf("global capture \"%s\" is not \"this is a foobarsystem\"", res[0][0]) } v = New().Anything().Find("foo").BeginCapture().Find("bar").Word().EndCapture() res = v.Regex().FindAllStringSubmatch(s, -1) if len(res) != 1 { t.Errorf("%v is not slice length 1", res) } if res[0][0] != "this is a foobarsystem" { t.Errorf("global capture \"%s\" is not \"this is a foobarsystem\"", res[0][0]) } if res[0][1] != "barsystem" { t.Errorf("capture %s is not barsystem", res[0][1]) } } func TestSeveralCaptures(t *testing.T) { s := ` this is a foobarsystem that matches my test And there, a new foobartest that should be ok ` v := New().Anything().Find("foo"). BeginCapture(). Find("bar").Word(). EndCapture(). SearchOneLine(false) res := v.Regex().FindAllStringSubmatch(s, -1) for i, r := range res { switch i { case 0: if r[1] != "barsystem" { t.Errorf("%s is not \"barsystem\"", r[1]) } case 1: if r[1] != "bartest" { t.Errorf("%s is not \"bartest\"", r[1]) } default: t.Errorf("%v is not allowed result", r) } } } func TestCaptureSeveralTimes(t *testing.T) { v := New(). BeginCapture(). Find("http"). // find http Maybe("s"). // + s if any Find("://"). EndCapture(). // stop, so we will capture http:// and https:// BeginCapture(). Find("www.").Anything(). // capture url: www.google.com EndCapture() c := v.Captures("http://www.google.com") if len(c) != 1 { t.Errorf("capture length is not 1: %d", len(c)) } if c[0][1] != "http://" { t.Errorf("first group should be http://, found: %s", c[0][1]) } if c[0][2] != "www.google.com" { t.Errorf("first group should be www.google.com, found: %s", c[0][2]) } } func TestCapturingSeveralGroups(t *testing.T) { s := ` test 1 foo 2 ` v := New(). Find(""). BeginCapture(). Word(). EndCapture(). Any(" "). BeginCapture(). Range("0", "9"). EndCapture(). Find("") res := v.Captures(s) if len(res) != 2 { t.Errorf("%v is not length 2", res) } for i, r := range res { switch i { case 0: if r[1] != "test" || r[2] != "1" { t.Errorf("%s,%s is not test,1", r[1], r[2]) } case 1: if r[1] != "foo" || r[2] != "2" { t.Errorf("%s,%s is not test,1", r[1], r[2]) } default: t.Errorf("%d is not a valid result index for %v", i, res) } } } func TestORMethod(t *testing.T) { s := "foobarbaz footestbaz foonobaz" expected := []string{"foobarbaz", "footestbaz"} v := New().Find("foobarbaz").Or(New().Find("footestbaz")) if !v.Test(s) { t.Errorf("%s doesn't match %s", v.Regex(), s) } res := []string{} res = v.Regex().FindAllString(s, -1) if len(res) != 2 { t.Errorf("%v is not length 2", res) } for i, r := range res { if r != expected[i] { t.Errorf("%s is not expected value: %s", r, expected[i]) } } } func TestMultipleMethod(t *testing.T) { v := New().Multiple("foo") assertStringEquals(v.Regex().String(), "(?m)(?:foo)+", t) // it the same... but to cover... v = New().Multiple("foo", 1) assertStringEquals(v.Regex().String(), "(?m)(?:foo)+", t) v = New().Multiple("foo", 0) assertStringEquals(v.Regex().String(), "(?m)(?:foo)*", t) v = New().Multiple("foo", 0, 1) assertStringEquals(v.Regex().String(), "(?m)(?:foo)?", t) v = New().Multiple("foo", 0, 10) assertStringEquals(v.Regex().String(), "(?m)(?:foo){,10}", t) v = New().Multiple("foo", 10) assertStringEquals(v.Regex().String(), "(?m)(?:foo){10,}", t) v = New().Multiple("foo", 10, 10) assertStringEquals(v.Regex().String(), "(?m)(?:foo){10,10}", t) v = New().Multiple("foo", 1, 10) assertStringEquals(v.Regex().String(), "(?m)(?:foo){1,10}", t) } func TestPanicMultipleMethod(t *testing.T) { defer func() { if r := recover(); r == nil { t.Errorf("We should have panic here !") } }() _ = New().Multiple("foo", 1, 10, 15) } func TestSomethingMethods(t *testing.T) { s := "abcdefghi" v := New().Find("ab").Something().Find("ef") res := v.Regex().FindAllString(s, -1) if res[0] != "abcdef" { t.Errorf("%v hasn't %s ", res, "abcdef") } v = New().Find("ab").SomethingBut("d") res = v.Regex().FindAllString(s, -1) if res[0] != "abc" { t.Errorf("%v hasn't %s ", res, "abc") } } func TestAllWithDot(t *testing.T) { s := ` foo bar baz ` v := New().Find("bar").Anything().Then("baz") res := v.Test(s) if res { t.Errorf("Error, %s should not match bar.baz", v.Regex()) } v.MatchAllWithDot(true) res = v.Test(s) if !res { t.Errorf("Error, %s should match bar.baz", v.Regex()) } } func TestWithAnyCase(t *testing.T) { s := "A MESSAGE IN CAPS" v := New().Find("message").WithAnyCase(true) res := v.Test(s) if !res { t.Errorf("Error, message should match MESSAGE", v.Regex()) } } func TestModifiers(t *testing.T) { v := New() assertStringEquals(v.getFlags(), "m", t) v.SearchOneLine(true) assertStringEquals(v.getFlags(), "", t) v.SearchOneLine(false) assertStringEquals(v.getFlags(), "m", t) v.WithAnyCase(true) assertStringEquals(v.getFlags(), "mi", t) v.WithAnyCase(false) assertStringEquals(v.getFlags(), "m", t) v.MatchAllWithDot(true) assertStringEquals(v.getFlags(), "ms", t) v.MatchAllWithDot(false) assertStringEquals(v.getFlags(), "m", t) v.flags = 16 assertStringEquals(v.getFlags(), "", t) } func TestGlobalModifier(t *testing.T) { s := "aaa aab aba abc" v := New().BeginCapture().Find("aa").AnythingBut(" ").EndCapture() res := v.Captures(s) if len(res) != 2 { t.Errorf("Initial state, GLOBAL on: %v is not lenght 2", res) } v.StopAtFirst(true) res = v.Captures(s) if len(res) > 1 { t.Errorf("%v is not lenght 1", res) } v.StopAtFirst(false) res = v.Captures(s) if len(res) != 2 { t.Errorf("State 2, GLOBAL reactivated: %v is not lenght 2", res) } } func TestStartEndWithOR(t *testing.T) { s := ` foo no bar bar foo bar ok not test foo bar foo bar ` // This is a very hight problem // This should generate (?m)^(?:foo)$|^(?:bar)$ v := New(). StartOfLine(). Find("foo"). EndOfLine(). Or(New(). StartOfLine(). Find("bar"). EndOfLine()) t.Log(v.Regex()) res := v.Regex().FindAllStringSubmatch(s, -1) if len(res) != 3 { t.Errorf("%v is not length 3", res) } // another possibility v = New(). StartOfLine(). Find("foo"). EndOfLine(). Or(New().Find("bar")) res = v.Regex().FindAllStringSubmatch(s, -1) if len(res) != 6 { t.Errorf("%v is not length 6", res) } } func TestLineBreak(t *testing.T) { s := ` foo bar baz ` v := New().Find("foo").LineBreak().Find("bar") if !v.Test(s) { t.Errorf("%v should match %s", v.Regex(), s) } v = New().Find("foo").Br().Find("bar") if !v.Test(s) { t.Errorf("%v should match %s", v.Regex(), s) } } func TestTABMethod(t *testing.T) { s := "foo bar baz" v := New().Find("foo").Tab().Find("bar") r := v.Test(s) if !r { t.Errorf("%v should match %s", v.Regex(), s) } } func TestToString(t *testing.T) { res := tostring(int64(15)) if res != "15" { t.Errorf("%v is not string \"15\"", res) } res = tostring(uint64(15)) if res != "15" { t.Errorf("%v is not string \"15\"", res) } res = tostring(uint(15)) if res != "15" { t.Errorf("%v is not string \"15\"", res) } } func TestToStringMustPanic(t *testing.T) { defer func() { if r := recover(); r == nil { t.Errorf("ToString must panic with unsupported types") } }() s := make(chan int) _ = tostring(s) } func TestNotMethod(t *testing.T) { s := `foobarbaz footestbaz fooexceptingbaz foootherokbaz foofoofoo foonotcap ` v := New(). Find("foo"). BeginCapture(). Not("excepting"). EndCapture(). Then("baz") res := v.Captures(s) t.Log(res) if len(res) != 3 { t.Errorf("%v is not length 3", res) } for i, r := range res { switch i { case 0: if r[1] != "bar" { t.Errorf("%s is not bar", r) } case 1: if r[1] != "test" { t.Errorf("%s is not bar", r) } case 2: if r[1] != "otherok" { t.Errorf("%s is not bar", r) } } } } func TestAndOrCumulate(t *testing.T) { s := `AB BC AC BB CC A B B C A C C C` v1 := New().Find("B") t.Log(v1.Regex()) v2 := New().Find("c").WithAnyCase(true).Or(v1) // Find B or C v := New().Find("A").And(v2) // Find A and (B or C) t.Log(v.Regex()) res := v.Regex().FindAllStringSubmatch(s, -1) if len(res) != 2 { t.Errorf("%v is not length 2", res) } if res[0][0] != "AB" { t.Errorf("%v is not AB ", res[0][0]) } if res[1][0] != "AC" { t.Errorf("%v is not AC ", res[1][0]) } }