goft - 解答
実装の全体像
以下に goft の想定解答を示します。各関数は禁止されているライブラリを使用せず、基本的な操作のみで実装しています。
go.mod
module goft
go 1.21
goft.go - メイン実装
package goft
// ============================================
// Part 1: 文字判定関数
// ============================================
// IsAlpha はアルファベットかどうかを判定します
func IsAlpha(r rune) bool {
return IsUpper(r) || IsLower(r)
}
// IsDigit は数字かどうかを判定します
func IsDigit(r rune) bool {
return r >= '0' && r <= '9'
}
// IsAlnum は英数字かどうかを判定します
func IsAlnum(r rune) bool {
return IsAlpha(r) || IsDigit(r)
}
// IsSpace は空白文字かどうかを判定します
func IsSpace(r rune) bool {
return r == ' ' || r == '\t' || r == '\n' ||
r == '\r' || r == '\v' || r == '\f'
}
// IsPrint は印字可能文字かどうかを判定します
func IsPrint(r rune) bool {
return r >= 0x20 && r <= 0x7E
}
// IsUpper は大文字かどうかを判定します
func IsUpper(r rune) bool {
return r >= 'A' && r <= 'Z'
}
// IsLower は小文字かどうかを判定します
func IsLower(r rune) bool {
return r >= 'a' && r <= 'z'
}
// ToUpper は小文字を大文字に変換します
func ToUpper(r rune) rune {
if IsLower(r) {
return r - 'a' + 'A'
}
return r
}
// ToLower は大文字を小文字に変換します
func ToLower(r rune) rune {
if IsUpper(r) {
return r - 'A' + 'a'
}
return r
}
// ============================================
// Part 2: 文字列操作関数
// ============================================
// Strlen は文字列の長さ(rune数)を返します
func Strlen(s string) int {
count := 0
for range s {
count++
}
return count
}
// Strchr は文字列内で指定された文字を先頭から検索します
// 見つかった場合はインデックス、見つからない場合は-1を返します
func Strchr(s string, c rune) int {
for i, r := range s {
if r == c {
return i
}
}
return -1
}
// Strrchr は文字列内で指定された文字を末尾から検索します
func Strrchr(s string, c rune) int {
lastIndex := -1
for i, r := range s {
if r == c {
lastIndex = i
}
}
return lastIndex
}
// Strncmp は2つの文字列を最大n文字まで比較します
func Strncmp(s1, s2 string, n int) int {
runes1 := []rune(s1)
runes2 := []rune(s2)
for i := 0; i < n; i++ {
var r1, r2 rune
if i < len(runes1) {
r1 = runes1[i]
}
if i < len(runes2) {
r2 = runes2[i]
}
if r1 != r2 {
return int(r1) - int(r2)
}
// 両方とも終端に達した場合
if i >= len(runes1) && i >= len(runes2) {
return 0
}
}
return 0
}
// Strdup は文字列を複製します
func Strdup(s string) string {
runes := []rune(s)
result := make([]rune, len(runes))
for i, r := range runes {
result[i] = r
}
return string(result)
}
// Substr は部分文字列を返します
func Substr(s string, start, length int) string {
runes := []rune(s)
if start < 0 || start >= len(runes) {
return ""
}
end := start + length
if end > len(runes) {
end = len(runes)
}
return string(runes[start:end])
}
// Strjoin は2つの文字列を結合します
func Strjoin(s1, s2 string) string {
runes1 := []rune(s1)
runes2 := []rune(s2)
result := make([]rune, len(runes1)+len(runes2))
for i, r := range runes1 {
result[i] = r
}
for i, r := range runes2 {
result[len(runes1)+i] = r
}
return string(result)
}
// Strtrim は文字列の両端から指定された文字セットを削除します
func Strtrim(s string, set string) string {
runes := []rune(s)
setRunes := []rune(set)
inSet := func(r rune) bool {
for _, sr := range setRunes {
if r == sr {
return true
}
}
return false
}
// 先頭から削除
start := 0
for start < len(runes) && inSet(runes[start]) {
start++
}
// 末尾から削除
end := len(runes)
for end > start && inSet(runes[end-1]) {
end--
}
return string(runes[start:end])
}
// Split は文字列を区切り文字で分割します
func Split(s string, sep rune) []string {
if s == "" {
return []string{""}
}
var result []string
var current []rune
for _, r := range s {
if r == sep {
result = append(result, string(current))
current = nil
} else {
current = append(current, r)
}
}
result = append(result, string(current))
return result
}
// ============================================
// Part 3: 数値変換関数
// ============================================
// Atoi は文字列を整数に変換します
func Atoi(s string) int {
runes := []rune(s)
i := 0
// 先頭の空白をスキップ
for i < len(runes) && IsSpace(runes[i]) {
i++
}
if i >= len(runes) {
return 0
}
// 符号の処理
sign := 1
if runes[i] == '-' {
sign = -1
i++
} else if runes[i] == '+' {
i++
}
// 数値の変換
result := 0
for i < len(runes) && IsDigit(runes[i]) {
digit := int(runes[i] - '0')
result = result*10 + digit
i++
}
return sign * result
}
// Itoa は整数を文字列に変換します
func Itoa(n int) string {
if n == 0 {
return "0"
}
negative := false
if n < 0 {
negative = true
n = -n
}
var digits []rune
for n > 0 {
digit := rune(n%10 + '0')
digits = append([]rune{digit}, digits...)
n /= 10
}
if negative {
digits = append([]rune{'-'}, digits...)
}
return string(digits)
}
// ============================================
// Part 4: メモリ操作関数
// ============================================
// Memset はバイトスライスを指定されたバイトで埋めます
func Memset(b []byte, c byte, n int) []byte {
if b == nil || n <= 0 {
return b
}
if n > len(b) {
n = len(b)
}
for i := 0; i < n; i++ {
b[i] = c
}
return b
}
// Memcpy はバイトスライスをコピーします
func Memcpy(dst, src []byte, n int) []byte {
if dst == nil || src == nil || n <= 0 {
return dst
}
if n > len(src) {
n = len(src)
}
if n > len(dst) {
n = len(dst)
}
for i := 0; i < n; i++ {
dst[i] = src[i]
}
return dst
}
// Memmove はオーバーラップを考慮してバイトスライスをコピーします
func Memmove(dst, src []byte, n int) []byte {
if dst == nil || src == nil || n <= 0 {
return dst
}
if n > len(src) {
n = len(src)
}
if n > len(dst) {
n = len(dst)
}
// 一時バッファを使用してオーバーラップに対応
temp := make([]byte, n)
for i := 0; i < n; i++ {
temp[i] = src[i]
}
for i := 0; i < n; i++ {
dst[i] = temp[i]
}
return dst
}
// Memcmp は2つのバイトスライスを比較します
func Memcmp(s1, s2 []byte, n int) int {
if n <= 0 {
return 0
}
for i := 0; i < n; i++ {
var b1, b2 byte
if i < len(s1) {
b1 = s1[i]
}
if i < len(s2) {
b2 = s2[i]
}
if b1 != b2 {
return int(b1) - int(b2)
}
}
return 0
}
// Memchr はバイトスライス内で指定されたバイトを検索します
func Memchr(s []byte, c byte, n int) int {
if s == nil || n <= 0 {
return -1
}
if n > len(s) {
n = len(s)
}
for i := 0; i < n; i++ {
if s[i] == c {
return i
}
}
return -1
}
goft_test.go - テストコード
package goft
import "testing"
func TestIsAlpha(t *testing.T) {
tests := []struct {
input rune
expected bool
}{
{'a', true},
{'z', true},
{'A', true},
{'Z', true},
{'0', false},
{' ', false},
{'!', false},
}
for _, tt := range tests {
result := IsAlpha(tt.input)
if result != tt.expected {
t.Errorf("IsAlpha(%q) = %v, want %v", tt.input, result, tt.expected)
}
}
}
func TestStrlen(t *testing.T) {
tests := []struct {
input string
expected int
}{
{"", 0},
{"hello", 5},
{"こんにちは", 5},
{"hello世界", 7},
}
for _, tt := range tests {
result := Strlen(tt.input)
if result != tt.expected {
t.Errorf("Strlen(%q) = %d, want %d", tt.input, result, tt.expected)
}
}
}
func TestAtoi(t *testing.T) {
tests := []struct {
input string
expected int
}{
{"0", 0},
{"42", 42},
{"-42", -42},
{" 123", 123},
{"+456", 456},
{"123abc", 123},
{"", 0},
}
for _, tt := range tests {
result := Atoi(tt.input)
if result != tt.expected {
t.Errorf("Atoi(%q) = %d, want %d", tt.input, result, tt.expected)
}
}
}
func TestSplit(t *testing.T) {
tests := []struct {
input string
sep rune
expected []string
}{
{"a,b,c", ',', []string{"a", "b", "c"}},
{"hello", ',', []string{"hello"}},
{"", ',', []string{""}},
{"a,,b", ',', []string{"a", "", "b"}},
}
for _, tt := range tests {
result := Split(tt.input, tt.sep)
if len(result) != len(tt.expected) {
t.Errorf("Split(%q, %q) = %v, want %v", tt.input, tt.sep, result, tt.expected)
continue
}
for i := range result {
if result[i] != tt.expected[i] {
t.Errorf("Split(%q, %q)[%d] = %q, want %q", tt.input, tt.sep, i, result[i], tt.expected[i])
}
}
}
}