The string will only contain 0's or 4's. The string will start with 4. example: 444, 44, 40, 4400, 4440, etc. These all are valid strings but 404 is not valid. Currently, I am checking if 4 is present immediately after 0. I am not sure that this one is efficient one.
If you mean leading 4
and following 0
.
package main
import (
"regexp"
)
func check(s string) bool {
return regexp.MustCompile(`^4+0*$`).MatchString(s)
}
func main() {
for _, tt := range []string{"444", "44", "40", "4400", "4440"} {
if !check(tt) {
panic("want true: " + tt)
}
}
for _, tt := range []string{"404", "040"} {
if check(tt) {
panic("want false: " + tt)
}
}
}
package main
func check(s string) bool {
i := 0
r := []rune(s)
for i = 0; i < len(r); i++ {
if r[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < len(r); i++ {
if r[i] != '0' {
return false
}
}
return true
}
func main() {
for _, tt := range []string{"444", "44", "40", "4400", "4440"} {
if !check(tt) {
panic("want true: " + tt)
}
}
for _, tt := range []string{"404", "040"} {
if check(tt) {
panic("want false: " + tt)
}
}
}
func check(s string) bool {
i, l := 0, len(s)
for ; i < l; i++ {
if s[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < l; i++ {
if s[i] != '0' {
return false
}
}
return true
}
No RegExp
package main
import (
"fmt"
"strings"
)
func validate(str string) bool {
if strings.HasPrefix(str, "4") {
for i:= 0; i < len(str)-1; i++ {
if (str[i] == '0') && (str[i+1] == '4') {
return false
}
}
}else { return false }
return true
}
func main() {
data := []string{"4", "44", "4400", "4440", "404", "004"}
for _, val := range data {
fmt.Println(validate(val))
}
}
Output:
true
true
true
false
false
For example,
package main
import "fmt"
func isFourZero(s string) bool {
i := 0
var four bool
for ; i < len(s) && s[i] == '4'; i++ {
four = true
}
if four {
if i >= len(s) {
return true
}
var zero bool
for ; i < len(s) && s[i] == '0'; i++ {
zero = true
}
if zero {
if i >= len(s) {
return true
}
}
}
return false
}
func main() {
tests := []struct{ s string }{
{"444"}, {"44"}, {"40"}, {"4400"}, {"4440"}, {"404"}, {"004"},
}
for _, test := range tests {
fmt.Printf("%q \t %t
", test.s, isFourZero(test.s))
}
}
Output:
"444" true
"44" true
"40" true
"4400" true
"4440" true
"404" false
"004" false
Since we care about speed, let's look at some benchmarks:
BenchmarkIsFourZeroPeterSO-4 10000000 201 ns/op
BenchmarkValidateYogeshDesai-4 5000000 347 ns/op
BenchmarkCheckMattn-4 2000000 602 ns/op
fourzero_test.go
:
package main
import (
"strings"
"testing"
)
var tests = []struct{ s string }{
{"444"}, {"44"}, {"40"}, {"4400"}, {"4440"}, {"404"}, {"004"},
}
func BenchmarkIsFourZeroPeterSO(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
isFourZero(test.s)
}
}
}
func BenchmarkValidateYogeshDesai(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
validate(test.s)
}
}
}
func BenchmarkCheckMattn(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
check(test.s)
}
}
}
func isFourZero(s string) bool {
i := 0
var four bool
for ; i < len(s) && s[i] == '4'; i++ {
four = true
}
if four {
if i >= len(s) {
return true
}
var zero bool
for ; i < len(s) && s[i] == '0'; i++ {
zero = true
}
if zero {
if i >= len(s) {
return true
}
}
}
return false
}
func validate(str string) bool {
if strings.HasPrefix(str, "4") {
for i := 0; i < len(str)-1; i++ {
if (str[i] == '0') && (str[i+1] == '4') {
return false
}
}
} else {
return false
}
return true
}
func check(s string) bool {
i := 0
r := []rune(s)
for i = 0; i < len(r); i++ {
if r[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < len(r); i++ {
if r[i] != '0' {
return false
}
}
return true
}
The following is another implementation using only a single loop:
func yetAnotherValidation(s string) bool {
//INVALID: if empty OR not started with '4'
if len(s) == 0 || s[0] != '4' {
return false
}
//INVALID: if len(s) > 2 AND contains "404"
for k := 2; k < len(s); k++ {
if s[k] == '4' && s[k-1] == '0' && s[k-2] == '4' {
return false
}
}
return true
}
Note:
404
* (e.g. 404
, 4404
, 4040
, ...) is INVALID.If s
contains a character other than 0
or 4
, the result will be undefined (depending on the position of that character). If you need to ensure whether the input only contains 0
or 4
, then:
func yetAnotherValidation2(s string) bool {
//INVALID: if empty OR not started with '4'
if len(s) == 0 || s[0] != '4' {
return false
}
//INVALID: if second digit is not 0 or 4
if len(s) > 1 && s[1] != '0' && s[1] != '4' {
return false
}
//For len(s) > 2
for k := 2; k < len(s); k++ {
if s[k] == '4' && s[k-1] == '0' && s[k-2] == '4' {
return false
} else if s[k] != '0' && s[k] != '4' {
//Neither 0 nor 4
return false
}
}
return true
}
UPDATE:
Test and benchmark result:
=== RUN TestValidate
444 true
44 true
40 true
4400 true
4440 true
404 false
004 false
--- PASS: TestValidate (0.00s)
BenchmarkYetAnotherValidation-4 50000000 38.5 ns/op
BenchmarkYetAnotherValidation2-4 30000000 45.6 ns/op
BenchmarkIsFourZero-4 20000000 54.5 ns/op
BenchmarkCheckMattn-4 10000000 144 ns/op
BenchmarkCheckMattnFast-4 30000000 50.2 ns/op