Repository: vaskoz/dailycodingproblem-go (go)

Issue:
Day 277
Good morning! Here's your coding interview problem for today.

This problem was asked by Google.

UTF-8 is a character encoding that maps each symbol to one, two, three, or four bytes.

For example, the Euro sign, €, corresponds to the three bytes `11100010 10000010 10101100`. The rules for mapping characters are as follows:

For a single-byte character, the first bit must be zero.
For an n-byte character, the first byte starts with n ones and a zero. The other n - 1 bytes all start with 10.
Visually, this can be represented as follows.
```
 Bytes   |           Byte format
-----------------------------------------------
   1     | 0xxxxxxx
   2     | 110xxxxx 10xxxxxx
   3     | 1110xxxx 10xxxxxx 10xxxxxx
   4     | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
```
Write a program that takes in an array of integers representing byte values, and returns whether it is a valid UTF-8 encoding.

Pull request:
Day277
Resolves #563.

Patch:
diff --git a/README.md b/README.md
index f354034..5df437d 100644
--- a/README.md
+++ b/README.md
@@ -281,3 +281,4 @@ problems from
 * [Day 271](https://github.com/vaskoz/dailycodingproblem-go/issues/553)
 * [Day 272](https://github.com/vaskoz/dailycodingproblem-go/issues/555)
 * [Day 273](https://github.com/vaskoz/dailycodingproblem-go/issues/556)
+* [Day 277](https://github.com/vaskoz/dailycodingproblem-go/issues/563)
diff --git a/day277/problem.go b/day277/problem.go
new file mode 100644
index 0000000..1633e16
--- /dev/null
+++ b/day277/problem.go
@@ -0,0 +1,34 @@
+package day277
+
+// IsValidUTF8 returns true if the bits represent valid 1-4 byte
+// UTF8.
+// NOTE: Using a string of 0's and 1's to represent bits.
+func IsValidUTF8(bits string) bool {
+	if len(bits)%8 != 0 {
+		panic("bytes should be multiples of 8-bits")
+	}
+	for bits != "" {
+		switch {
+		case bits[0] == '0':
+			bits = bits[8:]
+		case bits[0:3] == "110":
+			if len(bits) < 10 || bits[8:10] != "10" {
+				return false
+			}
+			bits = bits[16:]
+		case bits[0:4] == "1110":
+			if len(bits) < 18 || bits[8:10] != "10" || bits[16:18] != "10" {
+				return false
+			}
+			bits = bits[24:]
+		case bits[0:5] == "11110":
+			if len(bits) < 26 || bits[8:10] != "10" || bits[16:18] != "10" || bits[24:26] != "10" {
+				return false
+			}
+			bits = bits[32:]
+		default:
+			return false
+		}
+	}
+	return true
+}


Test patch:
diff --git a/day277/problem_test.go b/day277/problem_test.go
new file mode 100644
index 0000000..53a5b3b
--- /dev/null
+++ b/day277/problem_test.go
@@ -0,0 +1,45 @@
+package day277
+
+import "testing"
+
+// nolint
+var testcases = []struct {
+	bits  string
+	valid bool
+}{
+	{"111000101000001010101100", true},
+	{"0111111100000000", true},
+	{"110000001000000001010101", true},
+	{"11110111101111111011100010000111", true},
+	{"11110111", false},
+	{"10000000", false},
+	{"11000000", false},
+	{"11100000", false},
+}
+
+func TestIsValidUTF8(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if result := IsValidUTF8(tc.bits); result != tc.valid {
+			t.Errorf("Given %s, expected %v, got %v", tc.bits, tc.valid, result)
+		}
+	}
+}
+
+func TestIsValidUTF8BadInput(t *testing.T) {
+	t.Parallel()
+	defer func() {
+		if err := recover(); err == nil {
+			t.Errorf("expected a panic with bad input")
+		}
+	}()
+	IsValidUTF8("10111")
+}
+
+func BenchmarkIsValidUTF8(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			IsValidUTF8(tc.bits)
+		}
+	}
+}