package main import ( "bytes" "fmt" "os" "regexp" "strconv" "strings" "time" ) // Generate a regex accepting any string but the string of concatenated numbers // lower_bound to upper_bound (each inclusive). func generate_regex(lower_bound, upper_bound, mode int) string { var not_str bytes.Buffer var buf bytes.Buffer // generate not_string for number := lower_bound; number <= upper_bound; number++ { not_str.WriteString(strconv.Itoa(number)) } not_string := not_str.String() l := len(not_string) // mode 3 = lookahead if mode == 3 { buf.WriteString("^(?!") buf.WriteString(not_string) buf.WriteString("$).*$") return buf.String() } buf.WriteString("^(") // strings with length smaller than not_string // mode 1 == |.|..|...|… if mode == 1 { for i := 0; i < l; i++ { buf.WriteString(strings.Repeat(".", i)) if i != l-1 { buf.WriteString("|") } } // mode 2 == .?.?.?.?… } else if mode == 2 { buf.WriteString(strings.Repeat(".?", l-1)) } buf.WriteString("|") // strings with length equal to not_string for index := 0; index < l; index++ { buf.WriteString(strings.Repeat(".", index)) buf.WriteString("[^") buf.WriteString(string(not_string[index])) buf.WriteString("]") buf.WriteString(strings.Repeat(".", l-index-1)) if index != l-1 { buf.WriteString("|") } } buf.WriteString("|") // strings with length greater than not_string buf.WriteString(strings.Repeat(".", l)) buf.WriteString(".+") buf.WriteString(")$") return buf.String() } // Generate less than `(upper_bound - lower_bound)^2` input strings. // Returns testsuite dict. func generate_input_strings(lower_bound, upper_bound int) map[string]bool { testsuite := make(map[string]bool) // generate not_string var not_str bytes.Buffer for number := lower_bound; number <= upper_bound; number++ { not_str.WriteString(strconv.Itoa(number)) } not_string := not_str.String() // generate strings for begin := lower_bound; begin <= upper_bound; begin++ { for end := begin + 1; end <= upper_bound; end++ { var input_string = not_string[begin:end] matches := (input_string != not_string) testsuite[input_string] = matches } } return testsuite } // A helper for measuring time func trackingTime(begin time.Time) { elapsed := time.Since(begin) fmt.Printf("It takes %s to test all input strings.", elapsed) } // Actually run all pattern searches. func run_test(pat *regexp.Regexp, testsuite map[string]bool) { defer trackingTime(time.Now()) for input, match := range testsuite { //mat := pat.FindStringIndex(input) //matches := (mat != nil) matches := pat.MatchString(input) if match != matches { fmt.Printf("FAIL for %s (should be %t)\n", input, matches) return } } } func main() { low := 1 upp := 500 regex := generate_regex(low, upp, 1) fmt.Println(regex) fmt.Println("\n\n\n\n") testsuite := generate_input_strings(low, upp) fmt.Printf("Generated regex of string length %d.\n", len(regex)) fmt.Printf("Generated %d input strings.\n", len(testsuite)) pat := regexp.MustCompile(regex) fmt.Println("Regex compilation has finished.\n") run_test(pat, testsuite) os.Exit(0) }