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
===================
[](https://drone.io/github.com/VerbalExpressions/GoVerbalExpressions/latest)
[](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<<uint(i)) != 0 {
result = append(result, flag)
}
}
return string(result)
}
// add method, append expresions to the internal string that will be parsed
func (v *VerbalExpression) add(s string) *VerbalExpression {
v.compiled = false //reinit previous regexp compilation
v.expression += s
return v
}
// Start to capture something, stop with EndCapture()
func (v *VerbalExpression) BeginCapture() *VerbalExpression {
v.suffixes += ")"
return v.add("(")
}
// Stop capturing expresions parts
func (v *VerbalExpression) EndCapture() *VerbalExpression {
v.suffixes = strings.Replace(v.suffixes, ")", "", 1)
return v.add(")")
}
// Anything will match any char
func (v *VerbalExpression) Anything() *VerbalExpression {
return v.add(`(?:.*)`)
}
// AnythingBut will match anything excpeting the given string.
func (v *VerbalExpression) AnythingBut(s string) *VerbalExpression {
return v.add(`(?:[^` + quote(s) + `]*)`)
}
// Something matches at least one char
func (v *VerbalExpression) Something() *VerbalExpression {
return v.add(`(?:.+)`)
}
// Same as Something but excepting chars given in string "s"
func (v *VerbalExpression) SomethingBut(s string) *VerbalExpression {
return v.add(`(?:[^` + quote(s) + `]+)`)
}
// EndOfLine tells verbalexpressions to match a end of line.
// Warning, to check multiple line, you must use SearchOneLine(true)
func (v *VerbalExpression) EndOfLine() *VerbalExpression {
if !strings.HasSuffix(v.suffixes, "$") {
v.suffixes += "$"
}
return v
}
// Maybe will search string zero on more times
func (v *VerbalExpression) Maybe(s string) *VerbalExpression {
return v.add(`(?:` + quote(s) + `)?`)
}
// StartOfLine seeks the begining of a line. As EndOfLine you should use
// SearchOneLine(true) to test multiple lines
func (v *VerbalExpression) StartOfLine() *VerbalExpression {
if !strings.HasPrefix(v.prefixes, "^") {
v.prefixes = `^` + v.prefixes
}
return v
}
// Find seeks string. The string MUST be there (unlike Maybe() method)
func (v *VerbalExpression) Find(s string) *VerbalExpression {
return v.add(`(?:` + quote(s) + `)`)
}
// Not invert Find, meaning search something excepting "value". This
// is different than SomethingBut or AnythingBut that works with a list of
// caracters. Note that this method is not exactly the same as PCRE system.
//
// While PCRE allows: foo(?!bar)baz, "foobarrbaz" matches (note the double r).
// With our method, this doesn't match. But: "foobarbaz" doen't match (so it's ok).
// And "fooXXXbaz" matches also.
func (v *VerbalExpression) Not(value string) *VerbalExpression {
//return v.add(`(?!(` + quote(value) + `))`)
// because Golang doesn't implement ?!
// we create a pseudo negative system...
runes := []rune(quote(value))
parts := make([]string, 0)
prev := ""
for _, r := range runes {
parts = append(parts, prev+"[^"+string(r)+"]")
prev += string(r)
}
exp := strings.Join(parts, "|")
exp = "(?:" + exp + ")*?"
return v.add(exp)
}
// Alias to Find()
func (v *VerbalExpression) Then(s string) *VerbalExpression {
return v.Find(s)
}
// Any accepts caracters to be matched
func (v *VerbalExpression) Any(s string) *VerbalExpression {
return v.add(`(?:[` + quote(s) + `])`)
}
//AnyOf is an alias to Any
func (v *VerbalExpression) AnyOf(s string) *VerbalExpression {
return v.Any(s)
}
// LineBreak to find "\n" or "\r\n"
func (v *VerbalExpression) LineBreak() *VerbalExpression {
return v.add(`(?:(?:\n)|(?:\r\n))`)
}
// Alias to LineBreak
func (v *VerbalExpression) Br() *VerbalExpression {
return v.LineBreak()
}
// Range accepts an even number of arguments. Each pair of values defines start and end of range.
// Think like this: Range(from, to [, from, to ...])
func (v *VerbalExpression) Range(args ...interface{}) *VerbalExpression {
if len(args)%2 != 0 {
log.Panicf("Range: not even args number")
}
parts := make([]string, 3)
app := ""
for i := 0; i < len(args); i++ {
app += tostring(args[i])
if i%2 != 0 {
parts = append(parts, quote(app))
app = ""
} else {
app += "-"
}
}
return v.add("[" + strings.Join(parts, "") + "]")
}
// Tab fetch tabulation char (\t)
func (v *VerbalExpression) Tab() *VerbalExpression {
return v.add(`\t+`)
}
// Word matches any word (containing alpha char)
func (v *VerbalExpression) Word() *VerbalExpression {
return v.add(`\w+`)
}
// Multiply string s expression
//
// Multiple(value string [, min int[, max int]])
//
// This method accepts 1 to 3 arguments, argument 2 is min, argument 3 is max:
//
// // get "foo" at least one time
// v.Multiple("foo")
// v.Multiple("foo", 1)
//
// // get "foo" 0 or more times
// v.Multiple("foo", 0)
//
// //get "foo" 0 or 1 times
// v.Multiple("foo", 0, 1)
//
// // get "foo" 0 to 10 times
// v.Multiple("foo",0 ,10)
//
// //get "foo" at least 10 times
// v.Multiple("foo", 10)
//
// //get "foo" exactly 10 times
// v.Multiple("foo", 10, 10)
//
// //get "foo" from 1 to 10 times
// v.Multiple("foo", 1, 10)
func (v *VerbalExpression) Multiple(s string, mults ...int) *VerbalExpression {
if len(mults) > 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 := `
<b>test 1</b>
<b>foo 2</b>
`
v := New().
Find("<b>").
BeginCapture().
Word().
EndCapture().
Any(" ").
BeginCapture().
Range("0", "9").
EndCapture().
Find("</b>")
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])
}
}
gitextract_ib90aowl/ ├── .gitignore ├── LICENSE ├── README.md ├── doc.go ├── example_test.go ├── helpers.go ├── verbalexpressions.go └── verbalexpressions_test.go
SYMBOL INDEX (78 symbols across 4 files)
FILE: example_test.go
function ExampleVerbalExpression_Find (line 8) | func ExampleVerbalExpression_Find() {
function ExampleVerbalExpression_Captures (line 15) | func ExampleVerbalExpression_Captures() {
function ExampleVerbalExpression_Range (line 42) | func ExampleVerbalExpression_Range() {
function ExampleVerbalExpression_Any (line 51) | func ExampleVerbalExpression_Any() {
function ExampleVerbalExpression_Or (line 59) | func ExampleVerbalExpression_Or() {
function ExampleVerbalExpression_Replace (line 70) | func ExampleVerbalExpression_Replace() {
function ExampleVerbalExpression_AnythingBut (line 78) | func ExampleVerbalExpression_AnythingBut() {
FILE: helpers.go
method Test (line 6) | func (v *VerbalExpression) Test(s string) bool {
method Replace (line 12) | func (v *VerbalExpression) Replace(src string, dst string) string {
method Captures (line 18) | func (v *VerbalExpression) Captures(s string) [][]string {
FILE: verbalexpressions.go
type Flag (line 14) | type Flag
constant MULTILINE (line 17) | MULTILINE Flag = 1 << iota
constant IGNORE_CASE (line 18) | IGNORE_CASE
constant DOTALL (line 19) | DOTALL
constant UNGREEDY (line 20) | UNGREEDY
constant GLOBAL (line 21) | GLOBAL
type VerbalExpression (line 25) | type VerbalExpression struct
method addmodifier (line 73) | func (v *VerbalExpression) addmodifier(f Flag) *VerbalExpression {
method removemodifier (line 80) | func (v *VerbalExpression) removemodifier(f Flag) *VerbalExpression {
method getFlags (line 87) | func (v *VerbalExpression) getFlags() string {
method add (line 101) | func (v *VerbalExpression) add(s string) *VerbalExpression {
method BeginCapture (line 108) | func (v *VerbalExpression) BeginCapture() *VerbalExpression {
method EndCapture (line 114) | func (v *VerbalExpression) EndCapture() *VerbalExpression {
method Anything (line 120) | func (v *VerbalExpression) Anything() *VerbalExpression {
method AnythingBut (line 125) | func (v *VerbalExpression) AnythingBut(s string) *VerbalExpression {
method Something (line 130) | func (v *VerbalExpression) Something() *VerbalExpression {
method SomethingBut (line 135) | func (v *VerbalExpression) SomethingBut(s string) *VerbalExpression {
method EndOfLine (line 141) | func (v *VerbalExpression) EndOfLine() *VerbalExpression {
method Maybe (line 149) | func (v *VerbalExpression) Maybe(s string) *VerbalExpression {
method StartOfLine (line 155) | func (v *VerbalExpression) StartOfLine() *VerbalExpression {
method Find (line 163) | func (v *VerbalExpression) Find(s string) *VerbalExpression {
method Not (line 174) | func (v *VerbalExpression) Not(value string) *VerbalExpression {
method Then (line 193) | func (v *VerbalExpression) Then(s string) *VerbalExpression {
method Any (line 198) | func (v *VerbalExpression) Any(s string) *VerbalExpression {
method AnyOf (line 203) | func (v *VerbalExpression) AnyOf(s string) *VerbalExpression {
method LineBreak (line 208) | func (v *VerbalExpression) LineBreak() *VerbalExpression {
method Br (line 213) | func (v *VerbalExpression) Br() *VerbalExpression {
method Range (line 219) | func (v *VerbalExpression) Range(args ...interface{}) *VerbalExpression {
method Tab (line 239) | func (v *VerbalExpression) Tab() *VerbalExpression {
method Word (line 244) | func (v *VerbalExpression) Word() *VerbalExpression {
method Multiple (line 275) | func (v *VerbalExpression) Multiple(s string, mults ...int) *VerbalExp...
method Or (line 325) | func (v *VerbalExpression) Or(ve *VerbalExpression) *VerbalExpression {
method And (line 332) | func (v *VerbalExpression) And(ve *VerbalExpression) *VerbalExpression {
method WithAnyCase (line 337) | func (v *VerbalExpression) WithAnyCase(sensitive bool) *VerbalExpressi...
method SearchOneLine (line 346) | func (v *VerbalExpression) SearchOneLine(oneline bool) *VerbalExpressi...
method MatchAllWithDot (line 354) | func (v *VerbalExpression) MatchAllWithDot(enable bool) *VerbalExpress...
method Regex (line 362) | func (v *VerbalExpression) Regex() *regexp.Regexp {
method StopAtFirst (line 377) | func (v *VerbalExpression) StopAtFirst(enable bool) *VerbalExpression {
function quote (line 36) | func quote(s string) string {
function tostring (line 41) | func tostring(i interface{}) string {
function New (line 65) | func New() *VerbalExpression {
FILE: verbalexpressions_test.go
function assertStringEquals (line 9) | func assertStringEquals(s1, s2 string, t *testing.T) {
function TestChaining (line 15) | func TestChaining(t *testing.T) {
function TestRange (line 33) | func TestRange(t *testing.T) {
function TestPanicOnRangeOddParams (line 51) | func TestPanicOnRangeOddParams(t *testing.T) {
function TestOneLine (line 63) | func TestOneLine(t *testing.T) {
function TestAnythingBut (line 87) | func TestAnythingBut(t *testing.T) {
function TestAny (line 101) | func TestAny(t *testing.T) {
function TestReplace (line 118) | func TestReplace(t *testing.T) {
function TestCaptures (line 132) | func TestCaptures(t *testing.T) {
function TestSeveralCaptures (line 162) | func TestSeveralCaptures(t *testing.T) {
function TestCaptureSeveralTimes (line 193) | func TestCaptureSeveralTimes(t *testing.T) {
function TestCapturingSeveralGroups (line 219) | func TestCapturingSeveralGroups(t *testing.T) {
function TestORMethod (line 259) | func TestORMethod(t *testing.T) {
function TestMultipleMethod (line 283) | func TestMultipleMethod(t *testing.T) {
function TestPanicMultipleMethod (line 312) | func TestPanicMultipleMethod(t *testing.T) {
function TestSomethingMethods (line 321) | func TestSomethingMethods(t *testing.T) {
function TestAllWithDot (line 340) | func TestAllWithDot(t *testing.T) {
function TestWithAnyCase (line 360) | func TestWithAnyCase(t *testing.T) {
function TestModifiers (line 370) | func TestModifiers(t *testing.T) {
function TestGlobalModifier (line 396) | func TestGlobalModifier(t *testing.T) {
function TestStartEndWithOR (line 422) | func TestStartEndWithOR(t *testing.T) {
function TestLineBreak (line 464) | func TestLineBreak(t *testing.T) {
function TestTABMethod (line 481) | func TestTABMethod(t *testing.T) {
function TestToString (line 490) | func TestToString(t *testing.T) {
function TestToStringMustPanic (line 509) | func TestToStringMustPanic(t *testing.T) {
function TestNotMethod (line 522) | func TestNotMethod(t *testing.T) {
function TestAndOrCumulate (line 562) | func TestAndOrCumulate(t *testing.T) {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (32K chars).
[
{
"path": ".gitignore",
"chars": 6,
"preview": "*.swp\n"
},
{
"path": "LICENSE",
"chars": 1095,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2013 Patrice FERLET (metal3d.org)\n\nPermission is hereby granted, free of charge, to"
},
{
"path": "README.md",
"chars": 2678,
"preview": "GoVerbalExpressions\n===================\n\n[\n\nfunc ExampleVerba"
},
{
"path": "helpers.go",
"chars": 831,
"preview": "package verbalexpressions\n\n/* proxy and helpers to regexp.Regexp functions */\n\n// Test return true if verbalexpressions "
},
{
"path": "verbalexpressions.go",
"chars": 9714,
"preview": "// Copyright 2013 Patrice FERLET\n// Use of this source code is governed by MIT-style\n// license that can be found in the"
},
{
"path": "verbalexpressions_test.go",
"chars": 11629,
"preview": "// Copyright 2013 Patrice FERLET\n// Use of this source code is governed by MIT-style\n// license that can be found in the"
}
]
About this extraction
This page contains the full source code of the VerbalExpressions/GoVerbalExpressions GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (28.3 KB), approximately 8.8k tokens, and a symbol index with 78 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.