Screaming Snake Case - FreeCodeCamp #140 Daily Challenge
2 min
Problem Statement
Convert a variable name from any of these formats:
- camelCase:
"thisIsVariable" - PascalCase:
"ThisIsVariable" - snake_case:
"this_is_variable" - kebab-case:
"this-is-variable"
To SCREAMING_SNAKE_CASE:
- All letters in uppercase
- Words separated by underscores (
_)
Initial Analysis
Goal
Identify individual words regardless of the original format:
- Dashes:
-or_mark word boundaries - Uppercase letters: indicate the start of a new word in camelCase/PascalCase
Then join with _ and convert to uppercase.
Test Cases
| Input | Output | Format |
|---|---|---|
"userEmail" | "USER_EMAIL" | camelCase |
"UserPassword" | "USER_PASSWORD" | PascalCase |
"user_id" | "USER_ID" | snake_case |
"user-address" | "USER_ADDRESS" | kebab-case |
"username" | "USERNAME" | simple word |
Strategy: Normalize → Transform
flowchart TD
A["Input<br/>(any format)"] --> B["Normalize to snake_case"]
B --> C["Split by '_'"]
C --> D["toUpperCase() each word"]
D --> E["Join with '_'"]
E --> F["SCREAMING_SNAKE_CASE"]
style A fill:#e1f5ff
style F fill:#c8e6c9
Implementation
function toScreamingSnakeCase(variableName) {
// 1. Insert _ before uppercase: "userEmail" → "user_Email"
const withUnderscores = variableName.replace(/([a-z])([A-Z])/g, '$1_$2')
// 2. Normalize dashes: "user-address" → "user_address"
const normalized = withUnderscores.replace(/-/g, '_')
// 3. Split: "user_Email" → ["user", "Email"]
const words = normalized.split('_')
// 4. Uppercase + join: ["user", "Email"] → "USER_EMAIL"
return words.map(word => word.toUpperCase()).join('_')
}Complexity Analysis
Time:
Each operation traverses the string linearly:
| Operation | Complexity | Description |
|---|---|---|
replace (regex) | Examines each character once | |
replace (dashes) | Traverses the entire string | |
split('_') | Splits the string | |
map().join() | Iterates words and rebuilds |
Total:
Space:
Auxiliary structures created:
- Intermediate strings (
withUnderscores,normalized) wordsarray with extracted words- Output string
All proportional to the input length.
Edge Cases
✅ Handled Correctly
| Input | Output | Note |
|---|---|---|
"" | "" | Empty string |
"username" | "USERNAME" | Simple word |
"aB" | "A_B" | Individual letters |
"mixedFormat_case" | "MIXED_FORMAT_CASE" | Combined formats |
⚠️ Limitations
Acronyms: "XMLParser" → "X_M_L_PARSER" (each uppercase generates separation)
Numbers: "user2Email" → "USER2EMAIL" (current regex doesn’t detect numbers as boundaries)
Consecutive underscores: "user__email" → "USER__EMAIL" (preserved)
Reflections
Key Concepts
- Regex with capture groups:
/([a-z])([A-Z])/g+'$1_$2'inserts characters between groups - Data normalization: Converting multiple formats to an intermediate one reduces complexity
- Functional pipeline:
replace → split → map → joinis declarative and readable - Simple vs. complex regex: A single regex handling all cases would be harder to maintain. Clarity over brevity.
What I Learned
✨ Normalizing first simplifies the problem ✨ Regex with $1, $2 enables precise insertions ✨ split → map → join is a common pattern in text transformations