Basic keys parsing
diff --git a/keysparsing.go b/keysparsing.go
new file mode 100644
index 0000000..6bdb0b8
--- /dev/null
+++ b/keysparsing.go
@@ -0,0 +1,55 @@
+// Parsing keys handling both bare and quoted keys.
+
+package toml
+
+import (
+	"bytes"
+	"fmt"
+)
+
+func parseKey(key string) ([]string, error) {
+	groups := []string{}
+	var buffer bytes.Buffer
+	inQuotes := false
+	escapeNext := false
+	for _, char := range key {
+		if escapeNext {
+			buffer.WriteRune(char)
+			escapeNext = false
+			continue
+		}
+		switch char {
+		case '\\':
+			escapeNext = true
+			continue
+		case '"':
+			inQuotes = !inQuotes
+		case '.':
+			if inQuotes {
+				buffer.WriteRune(char)
+			} else {
+				groups = append(groups, buffer.String())
+				buffer.Reset()
+			}
+		default:
+			if !inQuotes && !isValidBareChar(char) {
+				return nil, fmt.Errorf("invalid bare character: %c", char)
+			}
+			buffer.WriteRune(char)
+		}
+	}
+	if inQuotes {
+		return nil, fmt.Errorf("mismatched quotes")
+	}
+	if escapeNext {
+		return nil, fmt.Errorf("unfinished escape sequence")
+	}
+	if buffer.Len() > 0 {
+		groups = append(groups, buffer.String())
+	}
+	return groups, nil
+}
+
+func isValidBareChar(r rune) bool {
+	return isAlphanumeric(r) || r == '-'
+}
diff --git a/keysparsing_test.go b/keysparsing_test.go
new file mode 100644
index 0000000..2d5379f
--- /dev/null
+++ b/keysparsing_test.go
@@ -0,0 +1,44 @@
+package toml
+
+import (
+	"fmt"
+	"testing"
+)
+
+func testResult(t *testing.T, key string, expected []string) {
+	parsed, err := parseKey(key)
+	if err != nil {
+		t.Fatal("Unexpected error:", err)
+	}
+	if len(expected) != len(parsed) {
+		t.Fatal("Expected length", len(expected), "but", len(parsed), "parsed")
+	}
+	for index, expectedKey := range expected {
+		if expectedKey != parsed[index] {
+			t.Fatal("Expected", expectedKey, "at index", index, "but found", parsed[index])
+		}
+	}
+}
+
+func testError(t *testing.T, key string, expectedError string) {
+	_, err := parseKey(key)
+	if fmt.Sprintf("%s", err) != expectedError {
+		t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
+	}
+}
+
+func TestBareKeyBasic(t *testing.T) {
+	testResult(t, "test", []string{"test"})
+}
+
+func TestBareKeyDotted(t *testing.T) {
+	testResult(t, "this.is.a.key", []string{"this", "is", "a", "key"})
+}
+
+func TestDottedKeyBasic(t *testing.T) {
+	testResult(t, "\"a.dotted.key\"", []string{"a.dotted.key"})
+}
+
+func TestBaseKeyPound(t *testing.T) {
+	testError(t, "hello#world", "invalid bare character: #")
+}
diff --git a/parser.go b/parser.go
index e83647d..e4d1083 100644
--- a/parser.go
+++ b/parser.go
@@ -98,7 +98,10 @@
 	}
 
 	// get or create group array element at the indicated part in the path
-	keys := strings.Split(key.val, ".")
+	keys, err := parseKey(key.val)
+	if err != nil {
+		p.raiseError(key, "invalid group array key: %s", err)
+	}
 	p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
 	destTree := p.tree.GetPath(keys)
 	var array []*TomlTree
@@ -153,7 +156,10 @@
 	}
 
 	p.seenGroupKeys = append(p.seenGroupKeys, key.val)
-	keys := strings.Split(key.val, ".")
+	keys, err := parseKey(key.val)
+	if err != nil {
+		p.raiseError(key, "invalid group array key: %s", err)
+	}
 	if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
 		p.raiseError(key, "%s", err)
 	}
diff --git a/parser_test.go b/parser_test.go
index dc051ea..d33ddde 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -461,3 +461,10 @@
 			"foo.bar.b": Position{3, 1},
 		})
 }
+
+func TestInvalidGroupArray(t *testing.T) {
+	_, err := Load("[key#group]\nanswer = 42")
+	if err == nil {
+		t.Error("Should error")
+	}
+}