From bc83ffccb2a391b2e4f82627a3f421d2f515f871 Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Sun, 5 Oct 2025 13:10:32 +0530 Subject: [PATCH 1/6] [Concept] Regular Expressions-add exercise templates --- internal/exercises/catalog.yaml | 12 +++ .../exercises/templates/28_regex/regex.go | 37 +++++++ .../templates/28_regex/regex_test.go | 99 +++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 internal/exercises/templates/28_regex/regex.go create mode 100644 internal/exercises/templates/28_regex/regex_test.go diff --git a/internal/exercises/catalog.yaml b/internal/exercises/catalog.yaml index f60c3bd..3637cdb 100644 --- a/internal/exercises/catalog.yaml +++ b/internal/exercises/catalog.yaml @@ -134,6 +134,18 @@ concepts: test_regex: ".*" hints: - Define a custom error type and return it from a function. +- slug: 28_regex + title: Regular Expressions + test_regex: ".*" + hints: + - Use regexp.MustCompile to create compiled regular expressions. + - Use MatchString to test if a string matches a pattern. + - Use FindAllString to extract all matches from text. + - Use ReplaceAllString to replace matches with new text. + - "Email regex: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" + - "Phone regex: ^\\(\\d{3}\\) \\d{3}-\\d{4}$" + - "Number regex: \\d+\\.?\\d*" + - "Vowel regex: [aeiouAEIOU]" - slug: 37_xml title: XML Encoding and Decoding test_regex: ".*" diff --git a/internal/exercises/templates/28_regex/regex.go b/internal/exercises/templates/28_regex/regex.go new file mode 100644 index 0000000..d53b161 --- /dev/null +++ b/internal/exercises/templates/28_regex/regex.go @@ -0,0 +1,37 @@ +package regex + +// Task: +// Implement regular expression functions using Go's regexp package. +// +// 1. Implement IsValidEmail to validate email addresses using regex. +// 2. Implement ExtractNumbers to extract all numbers from a string. +// 3. Implement ReplaceVowels to replace all vowels with asterisks. +// 4. Implement IsPhoneNumber to validate phone numbers in format (XXX) XXX-XXXX. + +// IsValidEmail should return true if the email address is valid. +// A valid email should have the format: user@domain.com +func IsValidEmail(email string) bool { + // TODO: implement using regexp.MustCompile and MatchString + return false +} + +// ExtractNumbers should return all numbers found in the input string. +// Numbers can be integers or decimals (e.g., "123", "45.67"). +func ExtractNumbers(text string) []string { + // TODO: implement using regexp.FindAllString + return nil +} + +// ReplaceVowels should replace all vowels (a, e, i, o, u) with asterisks. +// Case-insensitive replacement. +func ReplaceVowels(text string) string { + // TODO: implement using regexp.MustCompile and ReplaceAllString + return "" +} + +// IsPhoneNumber should return true if the phone number matches format (XXX) XXX-XXXX. +// Example: (123) 456-7890 +func IsPhoneNumber(phone string) bool { + // TODO: implement using regexp.MustCompile and MatchString + return false +} diff --git a/internal/exercises/templates/28_regex/regex_test.go b/internal/exercises/templates/28_regex/regex_test.go new file mode 100644 index 0000000..087b45a --- /dev/null +++ b/internal/exercises/templates/28_regex/regex_test.go @@ -0,0 +1,99 @@ +package regex + +import "testing" + +func TestIsValidEmail(t *testing.T) { + tests := []struct { + email string + expected bool + }{ + {"user@domain.com", true}, + {"test.email@example.org", true}, + {"invalid-email", false}, + {"@domain.com", false}, + {"user@", false}, + {"user@domain", false}, + {"", false}, + } + + for _, test := range tests { + result := IsValidEmail(test.email) + if result != test.expected { + t.Errorf("IsValidEmail(%q) = %v, want %v", test.email, result, test.expected) + } + } +} + +func TestExtractNumbers(t *testing.T) { + tests := []struct { + text string + expected []string + }{ + {"I have 123 apples and 45.67 oranges", []string{"123", "45.67"}}, + {"The price is $99.99", []string{"99.99"}}, + {"No numbers here", []string{}}, + {"123", []string{"123"}}, + {"12.34.56", []string{"12.34", "56"}}, + {"", []string{}}, + } + + for _, test := range tests { + result := ExtractNumbers(test.text) + if len(result) != len(test.expected) { + t.Errorf("ExtractNumbers(%q) length = %d, want %d", test.text, len(result), len(test.expected)) + continue + } + for i, num := range result { + if num != test.expected[i] { + t.Errorf("ExtractNumbers(%q)[%d] = %q, want %q", test.text, i, num, test.expected[i]) + } + } + } +} + +func TestReplaceVowels(t *testing.T) { + tests := []struct { + text string + expected string + }{ + {"hello", "h*ll*"}, + {"HELLO", "H*LL*"}, + {"Hello World", "H*ll* W*rld"}, + {"bcdfg", "bcdfg"}, + {"", ""}, + {"aeiou", "*****"}, + {"AEIOU", "*****"}, + } + + for _, test := range tests { + result := ReplaceVowels(test.text) + if result != test.expected { + t.Errorf("ReplaceVowels(%q) = %q, want %q", test.text, result, test.expected) + } + } +} + +func TestIsPhoneNumber(t *testing.T) { + tests := []struct { + phone string + expected bool + }{ + {"(123) 456-7890", true}, + {"(555) 123-4567", true}, + {"(000) 000-0000", true}, + {"123-456-7890", false}, + {"(123)456-7890", false}, + {"(123) 4567890", false}, + {"123 456 7890", false}, + {"(123) 456-789", false}, + {"(12) 456-7890", false}, + {"", false}, + } + + for _, test := range tests { + result := IsPhoneNumber(test.phone) + if result != test.expected { + t.Errorf("IsPhoneNumber(%q) = %v, want %v", test.phone, result, test.expected) + } + } +} From 351126ba9acc42ad4b9d54add5fe4e3bd3cfd002 Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Thu, 16 Oct 2025 10:57:34 +0530 Subject: [PATCH 2/6] Remove old 28_regex directory after renaming to 41_regex --- .../exercises/templates/28_regex/regex.go | 37 ------- .../templates/28_regex/regex_test.go | 99 ------------------- 2 files changed, 136 deletions(-) delete mode 100644 internal/exercises/templates/28_regex/regex.go delete mode 100644 internal/exercises/templates/28_regex/regex_test.go diff --git a/internal/exercises/templates/28_regex/regex.go b/internal/exercises/templates/28_regex/regex.go deleted file mode 100644 index d53b161..0000000 --- a/internal/exercises/templates/28_regex/regex.go +++ /dev/null @@ -1,37 +0,0 @@ -package regex - -// Task: -// Implement regular expression functions using Go's regexp package. -// -// 1. Implement IsValidEmail to validate email addresses using regex. -// 2. Implement ExtractNumbers to extract all numbers from a string. -// 3. Implement ReplaceVowels to replace all vowels with asterisks. -// 4. Implement IsPhoneNumber to validate phone numbers in format (XXX) XXX-XXXX. - -// IsValidEmail should return true if the email address is valid. -// A valid email should have the format: user@domain.com -func IsValidEmail(email string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} - -// ExtractNumbers should return all numbers found in the input string. -// Numbers can be integers or decimals (e.g., "123", "45.67"). -func ExtractNumbers(text string) []string { - // TODO: implement using regexp.FindAllString - return nil -} - -// ReplaceVowels should replace all vowels (a, e, i, o, u) with asterisks. -// Case-insensitive replacement. -func ReplaceVowels(text string) string { - // TODO: implement using regexp.MustCompile and ReplaceAllString - return "" -} - -// IsPhoneNumber should return true if the phone number matches format (XXX) XXX-XXXX. -// Example: (123) 456-7890 -func IsPhoneNumber(phone string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} diff --git a/internal/exercises/templates/28_regex/regex_test.go b/internal/exercises/templates/28_regex/regex_test.go deleted file mode 100644 index 087b45a..0000000 --- a/internal/exercises/templates/28_regex/regex_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package regex - -import "testing" - -func TestIsValidEmail(t *testing.T) { - tests := []struct { - email string - expected bool - }{ - {"user@domain.com", true}, - {"test.email@example.org", true}, - {"invalid-email", false}, - {"@domain.com", false}, - {"user@", false}, - {"user@domain", false}, - {"", false}, - } - - for _, test := range tests { - result := IsValidEmail(test.email) - if result != test.expected { - t.Errorf("IsValidEmail(%q) = %v, want %v", test.email, result, test.expected) - } - } -} - -func TestExtractNumbers(t *testing.T) { - tests := []struct { - text string - expected []string - }{ - {"I have 123 apples and 45.67 oranges", []string{"123", "45.67"}}, - {"The price is $99.99", []string{"99.99"}}, - {"No numbers here", []string{}}, - {"123", []string{"123"}}, - {"12.34.56", []string{"12.34", "56"}}, - {"", []string{}}, - } - - for _, test := range tests { - result := ExtractNumbers(test.text) - if len(result) != len(test.expected) { - t.Errorf("ExtractNumbers(%q) length = %d, want %d", test.text, len(result), len(test.expected)) - continue - } - for i, num := range result { - if num != test.expected[i] { - t.Errorf("ExtractNumbers(%q)[%d] = %q, want %q", test.text, i, num, test.expected[i]) - } - } - } -} - -func TestReplaceVowels(t *testing.T) { - tests := []struct { - text string - expected string - }{ - {"hello", "h*ll*"}, - {"HELLO", "H*LL*"}, - {"Hello World", "H*ll* W*rld"}, - {"bcdfg", "bcdfg"}, - {"", ""}, - {"aeiou", "*****"}, - {"AEIOU", "*****"}, - } - - for _, test := range tests { - result := ReplaceVowels(test.text) - if result != test.expected { - t.Errorf("ReplaceVowels(%q) = %q, want %q", test.text, result, test.expected) - } - } -} - -func TestIsPhoneNumber(t *testing.T) { - tests := []struct { - phone string - expected bool - }{ - {"(123) 456-7890", true}, - {"(555) 123-4567", true}, - {"(000) 000-0000", true}, - {"123-456-7890", false}, - {"(123)456-7890", false}, - {"(123) 4567890", false}, - {"123 456 7890", false}, - {"(123) 456-789", false}, - {"(12) 456-7890", false}, - {"", false}, - } - - for _, test := range tests { - result := IsPhoneNumber(test.phone) - if result != test.expected { - t.Errorf("IsPhoneNumber(%q) = %v, want %v", test.phone, result, test.expected) - } - } -} From f835a555ed8af576e2401cb14ed65677c7c47339 Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Thu, 16 Oct 2025 11:20:07 +0530 Subject: [PATCH 3/6] [Concept] String Functions - add exercise templates --- internal/exercises/catalog.yaml | 9 ++ .../42_string_functions/string_functions.go | 38 +++++ .../42_string_functions/string_functions.go | 46 ++++++ .../string_functions_test.go | 153 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 internal/exercises/solutions/42_string_functions/string_functions.go create mode 100644 internal/exercises/templates/42_string_functions/string_functions.go create mode 100644 internal/exercises/templates/42_string_functions/string_functions_test.go diff --git a/internal/exercises/catalog.yaml b/internal/exercises/catalog.yaml index ea98c8a..c387a31 100644 --- a/internal/exercises/catalog.yaml +++ b/internal/exercises/catalog.yaml @@ -235,6 +235,15 @@ concepts: - "Phone regex: ^\\(\\d{3}\\) \\d{3}-\\d{4}$" - "Number regex: \\d+\\.?\\d*" - "Vowel regex: [aeiouAEIOU]" +- slug: 42_string_functions + title: String Functions + test_regex: ".*" + hints: + - Use strings.Contains to check if a substring exists in a string. + - Use strings.HasPrefix and strings.HasSuffix for prefix/suffix checking. + - Use strings.Index to find the position of a substring. + - Use strings.ToUpper and strings.ToLower for case conversion. + - Use strings.TrimSpace to remove leading and trailing whitespace. projects: - slug: 101_text_analyzer title: Text Analyzer (Easy) diff --git a/internal/exercises/solutions/42_string_functions/string_functions.go b/internal/exercises/solutions/42_string_functions/string_functions.go new file mode 100644 index 0000000..cdc2588 --- /dev/null +++ b/internal/exercises/solutions/42_string_functions/string_functions.go @@ -0,0 +1,38 @@ +package string_functions + +import "strings" + +// Contains checks if substr is within s +func Contains(s, substr string) bool { + return strings.Contains(s, substr) +} + +// HasPrefix tests whether the string s begins with prefix +func HasPrefix(s, prefix string) bool { + return strings.HasPrefix(s, prefix) +} + +// HasSuffix tests whether the string s ends with suffix +func HasSuffix(s, suffix string) bool { + return strings.HasSuffix(s, suffix) +} + +// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s +func Index(s, substr string) int { + return strings.Index(s, substr) +} + +// ToUpper returns s with all Unicode letters mapped to their upper case +func ToUpper(s string) string { + return strings.ToUpper(s) +} + +// ToLower returns s with all Unicode letters mapped to their lower case +func ToLower(s string) string { + return strings.ToLower(s) +} + +// TrimSpace returns s with all leading and trailing white space removed +func TrimSpace(s string) string { + return strings.TrimSpace(s) +} diff --git a/internal/exercises/templates/42_string_functions/string_functions.go b/internal/exercises/templates/42_string_functions/string_functions.go new file mode 100644 index 0000000..f8c0d60 --- /dev/null +++ b/internal/exercises/templates/42_string_functions/string_functions.go @@ -0,0 +1,46 @@ +package string_functions + +// TODO: Implement these functions using Go's strings package +// You'll need to import "strings" package when implementing the functions + +// Contains checks if substr is within s +func Contains(s, substr string) bool { + // TODO: use strings.Contains + return false // Intentionally wrong to simulate failing exercise +} + +// HasPrefix tests whether the string s begins with prefix +func HasPrefix(s, prefix string) bool { + // TODO: use strings.HasPrefix + return false // Intentionally wrong to simulate failing exercise +} + +// HasSuffix tests whether the string s ends with suffix +func HasSuffix(s, suffix string) bool { + // TODO: use strings.HasSuffix + return false // Intentionally wrong to simulate failing exercise +} + +// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s +func Index(s, substr string) int { + // TODO: use strings.Index + return -1 // Intentionally wrong to simulate failing exercise +} + +// ToUpper returns s with all Unicode letters mapped to their upper case +func ToUpper(s string) string { + // TODO: use strings.ToUpper + return "" // Intentionally wrong to simulate failing exercise +} + +// ToLower returns s with all Unicode letters mapped to their lower case +func ToLower(s string) string { + // TODO: use strings.ToLower + return "" // Intentionally wrong to simulate failing exercise +} + +// TrimSpace returns s with all leading and trailing white space removed +func TrimSpace(s string) string { + // TODO: use strings.TrimSpace + return "" // Intentionally wrong to simulate failing exercise +} diff --git a/internal/exercises/templates/42_string_functions/string_functions_test.go b/internal/exercises/templates/42_string_functions/string_functions_test.go new file mode 100644 index 0000000..9550c31 --- /dev/null +++ b/internal/exercises/templates/42_string_functions/string_functions_test.go @@ -0,0 +1,153 @@ +package string_functions + +import "testing" + +func TestContains(t *testing.T) { + tests := []struct { + s string + substr string + want bool + }{ + {"hello world", "world", true}, + {"hello world", "hello", true}, + {"hello world", "foo", false}, + {"", "", true}, + {"hello", "", true}, + } + + for _, tt := range tests { + t.Run(tt.s+" contains "+tt.substr, func(t *testing.T) { + if got := Contains(tt.s, tt.substr); got != tt.want { + t.Errorf("Contains(%q, %q) = %v, want %v", tt.s, tt.substr, got, tt.want) + } + }) + } +} + +func TestHasPrefix(t *testing.T) { + tests := []struct { + s string + prefix string + want bool + }{ + {"hello world", "hello", true}, + {"hello world", "world", false}, + {"", "", true}, + {"hello", "hello", true}, + } + + for _, tt := range tests { + t.Run(tt.s+" has prefix "+tt.prefix, func(t *testing.T) { + if got := HasPrefix(tt.s, tt.prefix); got != tt.want { + t.Errorf("HasPrefix(%q, %q) = %v, want %v", tt.s, tt.prefix, got, tt.want) + } + }) + } +} + +func TestHasSuffix(t *testing.T) { + tests := []struct { + s string + suffix string + want bool + }{ + {"hello world", "world", true}, + {"hello world", "hello", false}, + {"", "", true}, + {"hello", "hello", true}, + } + + for _, tt := range tests { + t.Run(tt.s+" has suffix "+tt.suffix, func(t *testing.T) { + if got := HasSuffix(tt.s, tt.suffix); got != tt.want { + t.Errorf("HasSuffix(%q, %q) = %v, want %v", tt.s, tt.suffix, got, tt.want) + } + }) + } +} + +func TestIndex(t *testing.T) { + tests := []struct { + s string + substr string + want int + }{ + {"hello world", "world", 6}, + {"hello world", "hello", 0}, + {"hello world", "foo", -1}, + {"", "", 0}, + {"hello", "l", 2}, + } + + for _, tt := range tests { + t.Run("index of "+tt.substr+" in "+tt.s, func(t *testing.T) { + if got := Index(tt.s, tt.substr); got != tt.want { + t.Errorf("Index(%q, %q) = %v, want %v", tt.s, tt.substr, got, tt.want) + } + }) + } +} + +func TestToUpper(t *testing.T) { + tests := []struct { + s string + want string + }{ + {"hello", "HELLO"}, + {"Hello World", "HELLO WORLD"}, + {"", ""}, + {"123", "123"}, + {"héllo", "HÉLLO"}, + } + + for _, tt := range tests { + t.Run("ToUpper("+tt.s+")", func(t *testing.T) { + if got := ToUpper(tt.s); got != tt.want { + t.Errorf("ToUpper(%q) = %q, want %q", tt.s, got, tt.want) + } + }) + } +} + +func TestToLower(t *testing.T) { + tests := []struct { + s string + want string + }{ + {"HELLO", "hello"}, + {"Hello World", "hello world"}, + {"", ""}, + {"123", "123"}, + {"HÉLLO", "héllo"}, + } + + for _, tt := range tests { + t.Run("ToLower("+tt.s+")", func(t *testing.T) { + if got := ToLower(tt.s); got != tt.want { + t.Errorf("ToLower(%q) = %q, want %q", tt.s, got, tt.want) + } + }) + } +} + +func TestTrimSpace(t *testing.T) { + tests := []struct { + s string + want string + }{ + {" hello ", "hello"}, + {" hello world ", "hello world"}, + {"", ""}, + {"hello", "hello"}, + {" ", ""}, + {"\n\thello\t\n", "hello"}, + } + + for _, tt := range tests { + t.Run("TrimSpace("+tt.s+")", func(t *testing.T) { + if got := TrimSpace(tt.s); got != tt.want { + t.Errorf("TrimSpace(%q) = %q, want %q", tt.s, got, tt.want) + } + }) + } +} From f501ede5ca1d0abe47a191451de15be2229d5af5 Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Thu, 16 Oct 2025 11:24:56 +0530 Subject: [PATCH 4/6] [Concept] String Functions - add exercise templates --- docs/exercises.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/exercises.md b/docs/exercises.md index 7a88f72..cd7771d 100644 --- a/docs/exercises.md +++ b/docs/exercises.md @@ -49,6 +49,8 @@ title: Exercises
  • 25_range_iterators - Range over Iterators
  • 26_errors - Error Handling
  • 27_custom_errors - Custom Errors
  • +
  • 41_regex - Regular Expressions
  • +
  • 42_string_functions - String Functions
  • 36_json - JSON Processing
  • 37_xml - XML Processing
  • From 89be674ed2d4cc517d5db83d5a16bffb8f5abe5e Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Sun, 2 Nov 2025 15:19:09 +0530 Subject: [PATCH 5/6] Limit PR scope to single exercise: remove regex, keep only string_functions (#77) - Removed all 41_regex exercise files (templates and solutions) - Removed 41_regex entry from catalog.yaml - Updated docs/exercises.md: - Removed regex reference - Reordered exercises (36_json, 37_xml before 44_string_functions) - Updated section header to 'Advanced (21-44)' - PR now focuses solely on String Functions exercise as requested --- docs/exercises.md | 5 +- internal/exercises/catalog.yaml | 12 --- .../exercises/solutions/41_regex/regex.go | 37 ------- .../exercises/templates/41_regex/regex.go | 37 ------- .../templates/41_regex/regex_test.go | 99 ------------------- 5 files changed, 2 insertions(+), 188 deletions(-) delete mode 100644 internal/exercises/solutions/41_regex/regex.go delete mode 100644 internal/exercises/templates/41_regex/regex.go delete mode 100644 internal/exercises/templates/41_regex/regex_test.go diff --git a/docs/exercises.md b/docs/exercises.md index 643b5c3..5e65948 100644 --- a/docs/exercises.md +++ b/docs/exercises.md @@ -40,7 +40,7 @@ title: Exercises
  • 20_methods - Methods
  • -

    Advanced (21-37)

    +

    Advanced (21-44)

    • 21_interfaces - Interfaces
    • 22_enums - Enums
    • @@ -49,10 +49,9 @@ title: Exercises
    • 25_range_iterators - Range over Iterators
    • 26_errors - Error Handling
    • 27_custom_errors - Custom Errors
    • -
    • 41_regex - Regular Expressions
    • -
    • 44_string_functions - String Functions
    • 36_json - JSON Processing
    • 37_xml - XML Processing
    • +
    • 44_string_functions - String Functions
    diff --git a/internal/exercises/catalog.yaml b/internal/exercises/catalog.yaml index 47244a8..a9f4471 100644 --- a/internal/exercises/catalog.yaml +++ b/internal/exercises/catalog.yaml @@ -223,18 +223,6 @@ concepts: hints: - Use `select` to handle multiple channel operations concurrently. - Use `time.After` to simulate a 5 microsecond timeout. -- slug: 41_regex - title: Regular Expressions - test_regex: ".*" - hints: - - Use regexp.MustCompile to create compiled regular expressions. - - Use MatchString to test if a string matches a pattern. - - Use FindAllString to extract all matches from text. - - Use ReplaceAllString to replace matches with new text. - - "Email regex: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" - - "Phone regex: ^\\(\\d{3}\\) \\d{3}-\\d{4}$" - - "Number regex: \\d+\\.?\\d*" - - "Vowel regex: [aeiouAEIOU]" - slug: 41_time_delay title: "Delays and Timers in Go" difficulty: beginner diff --git a/internal/exercises/solutions/41_regex/regex.go b/internal/exercises/solutions/41_regex/regex.go deleted file mode 100644 index d53b161..0000000 --- a/internal/exercises/solutions/41_regex/regex.go +++ /dev/null @@ -1,37 +0,0 @@ -package regex - -// Task: -// Implement regular expression functions using Go's regexp package. -// -// 1. Implement IsValidEmail to validate email addresses using regex. -// 2. Implement ExtractNumbers to extract all numbers from a string. -// 3. Implement ReplaceVowels to replace all vowels with asterisks. -// 4. Implement IsPhoneNumber to validate phone numbers in format (XXX) XXX-XXXX. - -// IsValidEmail should return true if the email address is valid. -// A valid email should have the format: user@domain.com -func IsValidEmail(email string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} - -// ExtractNumbers should return all numbers found in the input string. -// Numbers can be integers or decimals (e.g., "123", "45.67"). -func ExtractNumbers(text string) []string { - // TODO: implement using regexp.FindAllString - return nil -} - -// ReplaceVowels should replace all vowels (a, e, i, o, u) with asterisks. -// Case-insensitive replacement. -func ReplaceVowels(text string) string { - // TODO: implement using regexp.MustCompile and ReplaceAllString - return "" -} - -// IsPhoneNumber should return true if the phone number matches format (XXX) XXX-XXXX. -// Example: (123) 456-7890 -func IsPhoneNumber(phone string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} diff --git a/internal/exercises/templates/41_regex/regex.go b/internal/exercises/templates/41_regex/regex.go deleted file mode 100644 index d53b161..0000000 --- a/internal/exercises/templates/41_regex/regex.go +++ /dev/null @@ -1,37 +0,0 @@ -package regex - -// Task: -// Implement regular expression functions using Go's regexp package. -// -// 1. Implement IsValidEmail to validate email addresses using regex. -// 2. Implement ExtractNumbers to extract all numbers from a string. -// 3. Implement ReplaceVowels to replace all vowels with asterisks. -// 4. Implement IsPhoneNumber to validate phone numbers in format (XXX) XXX-XXXX. - -// IsValidEmail should return true if the email address is valid. -// A valid email should have the format: user@domain.com -func IsValidEmail(email string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} - -// ExtractNumbers should return all numbers found in the input string. -// Numbers can be integers or decimals (e.g., "123", "45.67"). -func ExtractNumbers(text string) []string { - // TODO: implement using regexp.FindAllString - return nil -} - -// ReplaceVowels should replace all vowels (a, e, i, o, u) with asterisks. -// Case-insensitive replacement. -func ReplaceVowels(text string) string { - // TODO: implement using regexp.MustCompile and ReplaceAllString - return "" -} - -// IsPhoneNumber should return true if the phone number matches format (XXX) XXX-XXXX. -// Example: (123) 456-7890 -func IsPhoneNumber(phone string) bool { - // TODO: implement using regexp.MustCompile and MatchString - return false -} diff --git a/internal/exercises/templates/41_regex/regex_test.go b/internal/exercises/templates/41_regex/regex_test.go deleted file mode 100644 index 087b45a..0000000 --- a/internal/exercises/templates/41_regex/regex_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package regex - -import "testing" - -func TestIsValidEmail(t *testing.T) { - tests := []struct { - email string - expected bool - }{ - {"user@domain.com", true}, - {"test.email@example.org", true}, - {"invalid-email", false}, - {"@domain.com", false}, - {"user@", false}, - {"user@domain", false}, - {"", false}, - } - - for _, test := range tests { - result := IsValidEmail(test.email) - if result != test.expected { - t.Errorf("IsValidEmail(%q) = %v, want %v", test.email, result, test.expected) - } - } -} - -func TestExtractNumbers(t *testing.T) { - tests := []struct { - text string - expected []string - }{ - {"I have 123 apples and 45.67 oranges", []string{"123", "45.67"}}, - {"The price is $99.99", []string{"99.99"}}, - {"No numbers here", []string{}}, - {"123", []string{"123"}}, - {"12.34.56", []string{"12.34", "56"}}, - {"", []string{}}, - } - - for _, test := range tests { - result := ExtractNumbers(test.text) - if len(result) != len(test.expected) { - t.Errorf("ExtractNumbers(%q) length = %d, want %d", test.text, len(result), len(test.expected)) - continue - } - for i, num := range result { - if num != test.expected[i] { - t.Errorf("ExtractNumbers(%q)[%d] = %q, want %q", test.text, i, num, test.expected[i]) - } - } - } -} - -func TestReplaceVowels(t *testing.T) { - tests := []struct { - text string - expected string - }{ - {"hello", "h*ll*"}, - {"HELLO", "H*LL*"}, - {"Hello World", "H*ll* W*rld"}, - {"bcdfg", "bcdfg"}, - {"", ""}, - {"aeiou", "*****"}, - {"AEIOU", "*****"}, - } - - for _, test := range tests { - result := ReplaceVowels(test.text) - if result != test.expected { - t.Errorf("ReplaceVowels(%q) = %q, want %q", test.text, result, test.expected) - } - } -} - -func TestIsPhoneNumber(t *testing.T) { - tests := []struct { - phone string - expected bool - }{ - {"(123) 456-7890", true}, - {"(555) 123-4567", true}, - {"(000) 000-0000", true}, - {"123-456-7890", false}, - {"(123)456-7890", false}, - {"(123) 4567890", false}, - {"123 456 7890", false}, - {"(123) 456-789", false}, - {"(12) 456-7890", false}, - {"", false}, - } - - for _, test := range tests { - result := IsPhoneNumber(test.phone) - if result != test.expected { - t.Errorf("IsPhoneNumber(%q) = %v, want %v", test.phone, result, test.expected) - } - } -} From dcf2014e128ca01f82197e179e037d00127cc0b6 Mon Sep 17 00:00:00 2001 From: Arya Soni Date: Wed, 26 Nov 2025 00:10:55 +0530 Subject: [PATCH 6/6] [Concept] String Functions - add exercise templates --- internal/exercises/catalog.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/exercises/catalog.yaml b/internal/exercises/catalog.yaml index 96e6734..d84a3f0 100644 --- a/internal/exercises/catalog.yaml +++ b/internal/exercises/catalog.yaml @@ -190,7 +190,7 @@ concepts: - Add XML struct tags using `xml:"fieldname"` to map struct fields to XML elements. - Use xml.Marshal to convert structs to XML bytes. - Use xml.Unmarshal to parse XML bytes into structs. -- slug: 37_sorting_by_functions +- slug: 48_sorting_by_functions title: "Sorting by Functions" difficulty: beginner topics: ["slices", "sorting", "functions"] @@ -282,7 +282,7 @@ concepts: - Use strings.Index to find the position of a substring. - Use strings.ToUpper and strings.ToLower for case conversion. - Use strings.TrimSpace to remove leading and trailing whitespace. -- slug: 39_panic +- slug: 49_panic title: Panic and Recover test_regex: ".*" hints: @@ -290,7 +290,7 @@ concepts: - "Use `defer` with `recover()` to catch and handle panics." - "Recovering from panics allows graceful handling of unexpected situations." - "Remember: `recover()` only works inside a deferred function." -- slug: 64_timers +- slug: 50_timers title: "Timers" difficulty: medium topics: ["time", "goroutines", "concurrency", "synchronization"] @@ -304,7 +304,7 @@ concepts: - "Reset can call timer.Reset(d) to reschedule the same callback." - "Remember to remove timers from the map after they fire to avoid memory leaks." - "Write tests to verify Start, Stop, and Reset behavior, including concurrency scenarios." -- slug: 68_rate_limiting +- slug: 51_rate_limiting title: Rate Limiting test_regex: ".*" difficulty: medium