javascript
exercises
exercises.js⚡javascript
/**
* ========================================
* 13.1 String Fundamentals - Exercises
* ========================================
*
* Practice working with JavaScript strings.
*/
/**
* EXERCISE 1: Character Access
*
* Write a function that returns the first, middle, and last
* characters of a string. Use .at() for negative indexing.
*/
function getCharacters(str) {
// YOUR CODE HERE:
// Return { first, middle, last }
}
// console.log(getCharacters('hello')); // { first: 'h', middle: 'l', last: 'o' }
// console.log(getCharacters('JavaScript')); // { first: 'J', middle: 'S', last: 't' }
/*
* SOLUTION:
*
* function getCharacters(str) {
* return {
* first: str.at(0),
* middle: str.at(Math.floor(str.length / 2)),
* last: str.at(-1)
* };
* }
*/
/**
* EXERCISE 2: Count Vowels and Consonants
*
* Count the number of vowels and consonants in a string.
* Only count letters (ignore numbers and special characters).
*/
function countLetters(str) {
// YOUR CODE HERE:
// Return { vowels, consonants }
}
// console.log(countLetters('Hello World')); // { vowels: 3, consonants: 7 }
// console.log(countLetters('JavaScript123')); // { vowels: 3, consonants: 7 }
/*
* SOLUTION:
*
* function countLetters(str) {
* const vowels = 'aeiouAEIOU';
* let vowelCount = 0;
* let consonantCount = 0;
*
* for (const char of str) {
* if (/[a-zA-Z]/.test(char)) {
* if (vowels.includes(char)) {
* vowelCount++;
* } else {
* consonantCount++;
* }
* }
* }
*
* return { vowels: vowelCount, consonants: consonantCount };
* }
*/
/**
* EXERCISE 3: Template Literal Builder
*
* Create a function that builds a formatted message
* using template literals.
*/
function buildMessage(user) {
// YOUR CODE HERE:
// Return formatted string like:
// "Hello, John Doe! You are 30 years old and live in NYC."
}
// const user = { firstName: 'John', lastName: 'Doe', age: 30, city: 'NYC' };
// console.log(buildMessage(user));
/*
* SOLUTION:
*
* function buildMessage(user) {
* return `Hello, ${user.firstName} ${user.lastName}! You are ${user.age} years old and live in ${user.city}.`;
* }
*/
/**
* EXERCISE 4: Case Converter
*
* Create functions for different case conversions:
* - toTitleCase: "hello world" → "Hello World"
* - toCamelCase: "hello world" → "helloWorld"
* - toSnakeCase: "Hello World" → "hello_world"
* - toKebabCase: "Hello World" → "hello-world"
*/
function caseConverter(str) {
// YOUR CODE HERE:
// Return { titleCase, camelCase, snakeCase, kebabCase }
}
// console.log(caseConverter('hello world'));
// {
// titleCase: 'Hello World',
// camelCase: 'helloWorld',
// snakeCase: 'hello_world',
// kebabCase: 'hello-world'
// }
/*
* SOLUTION:
*
* function caseConverter(str) {
* const words = str.toLowerCase().split(/\s+/);
*
* return {
* titleCase: words.map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
* camelCase: words.map((w, i) =>
* i === 0 ? w : w.charAt(0).toUpperCase() + w.slice(1)
* ).join(''),
* snakeCase: words.join('_'),
* kebabCase: words.join('-')
* };
* }
*/
/**
* EXERCISE 5: Find All Occurrences
*
* Find all indices where a substring appears.
*/
function findAllOccurrences(str, search) {
// YOUR CODE HERE:
// Return array of indices
}
// console.log(findAllOccurrences('abcabc', 'abc')); // [0, 3]
// console.log(findAllOccurrences('aaaa', 'aa')); // [0, 1, 2]
// console.log(findAllOccurrences('hello', 'x')); // []
/*
* SOLUTION:
*
* function findAllOccurrences(str, search) {
* const indices = [];
* let index = 0;
*
* while ((index = str.indexOf(search, index)) !== -1) {
* indices.push(index);
* index++; // Move forward to find overlapping matches
* }
*
* return indices;
* }
*/
/**
* EXERCISE 6: Word Counter
*
* Count words, sentences, and paragraphs in text.
*/
function analyzeText(text) {
// YOUR CODE HERE:
// Return { words, sentences, paragraphs }
}
// const text = `Hello World. This is a test.
//
// This is paragraph two.`;
// console.log(analyzeText(text));
// { words: 9, sentences: 3, paragraphs: 2 }
/*
* SOLUTION:
*
* function analyzeText(text) {
* const words = text.trim().split(/\s+/).filter(w => w.length > 0).length;
* const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0).length;
* const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim().length > 0).length;
*
* return { words, sentences, paragraphs };
* }
*/
/**
* EXERCISE 7: Truncate with Options
*
* Truncate a string with configurable options:
* - maxLength: maximum length including suffix
* - suffix: what to append (default '...')
* - wordBoundary: if true, don't cut words
*/
function truncate(str, options = {}) {
// YOUR CODE HERE:
// Return truncated string
}
// console.log(truncate('Hello World', { maxLength: 8 })); // 'Hello...'
// console.log(truncate('Hello World', { maxLength: 8, suffix: '…' })); // 'Hello W…'
// console.log(truncate('Hello World', { maxLength: 8, wordBoundary: true })); // 'Hello...'
/*
* SOLUTION:
*
* function truncate(str, options = {}) {
* const { maxLength = 20, suffix = '...', wordBoundary = false } = options;
*
* if (str.length <= maxLength) return str;
*
* let truncated = str.slice(0, maxLength - suffix.length);
*
* if (wordBoundary) {
* const lastSpace = truncated.lastIndexOf(' ');
* if (lastSpace > 0) {
* truncated = truncated.slice(0, lastSpace);
* }
* }
*
* return truncated + suffix;
* }
*/
/**
* EXERCISE 8: String Padding Formatter
*
* Format data into aligned columns.
*/
function formatTable(data, columnWidth) {
// YOUR CODE HERE:
// Return formatted string with aligned columns
}
// const data = [
// { name: 'Apple', price: 1.5 },
// { name: 'Banana', price: 0.75 },
// { name: 'Cherry', price: 2.0 }
// ];
// console.log(formatTable(data, 10));
// 'Apple $ 1.50'
// 'Banana $ 0.75'
// 'Cherry $ 2.00'
/*
* SOLUTION:
*
* function formatTable(data, columnWidth) {
* return data.map(item =>
* item.name.padEnd(columnWidth) +
* '$' + item.price.toFixed(2).padStart(8)
* ).join('\n');
* }
*/
/**
* EXERCISE 9: Parse URL
*
* Extract parts of a URL string without using URL API.
*/
function parseUrl(url) {
// YOUR CODE HERE:
// Return { protocol, domain, path, query }
}
// console.log(parseUrl('https://example.com/path/to/page?name=John&age=30'));
// {
// protocol: 'https',
// domain: 'example.com',
// path: '/path/to/page',
// query: { name: 'John', age: '30' }
// }
/*
* SOLUTION:
*
* function parseUrl(url) {
* const [protocolPart, rest] = url.split('://');
* const [domainAndPath, queryString] = rest.split('?');
* const [domain, ...pathParts] = domainAndPath.split('/');
* const path = '/' + pathParts.join('/');
*
* const query = {};
* if (queryString) {
* queryString.split('&').forEach(pair => {
* const [key, value] = pair.split('=');
* query[key] = value;
* });
* }
*
* return { protocol: protocolPart, domain, path, query };
* }
*/
/**
* EXERCISE 10: Replace Multiple
*
* Replace multiple substrings at once using a mapping object.
*/
function replaceMultiple(str, replacements) {
// YOUR CODE HERE:
// Replace all occurrences of each key with its value
}
// const text = 'Hello {name}, welcome to {city}!';
// console.log(replaceMultiple(text, { '{name}': 'John', '{city}': 'NYC' }));
// 'Hello John, welcome to NYC!'
/*
* SOLUTION:
*
* function replaceMultiple(str, replacements) {
* let result = str;
* for (const [search, replace] of Object.entries(replacements)) {
* result = result.replaceAll(search, replace);
* }
* return result;
* }
*
* // Alternative with regex:
* function replaceMultiple(str, replacements) {
* const pattern = new RegExp(
* Object.keys(replacements).map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'),
* 'g'
* );
* return str.replace(pattern, match => replacements[match]);
* }
*/
/**
* EXERCISE 11: Extract Hashtags
*
* Extract all hashtags from a social media post.
*/
function extractHashtags(text) {
// YOUR CODE HERE:
// Return array of hashtags (without #)
}
// console.log(extractHashtags('Hello #world! Check out #JavaScript and #coding'));
// ['world', 'JavaScript', 'coding']
/*
* SOLUTION:
*
* function extractHashtags(text) {
* const matches = text.match(/#\w+/g) || [];
* return matches.map(tag => tag.slice(1));
* }
*/
/**
* EXERCISE 12: Mask String
*
* Mask part of a string (like credit card or email).
*/
function maskString(str, options = {}) {
// YOUR CODE HERE:
// Options: { showFirst, showLast, maskChar }
}
// console.log(maskString('1234567890123456', { showFirst: 4, showLast: 4 }));
// '1234********3456'
// console.log(maskString('john@example.com', { showFirst: 2, showLast: 4 }));
// 'jo**********com'
/*
* SOLUTION:
*
* function maskString(str, options = {}) {
* const { showFirst = 0, showLast = 0, maskChar = '*' } = options;
*
* if (showFirst + showLast >= str.length) return str;
*
* const first = str.slice(0, showFirst);
* const last = str.slice(-showLast || str.length);
* const maskLength = str.length - showFirst - showLast;
*
* return first + maskChar.repeat(maskLength) + last;
* }
*/
/**
* EXERCISE 13: Word Wrap
*
* Wrap text to a specified line length.
*/
function wordWrap(text, maxLineLength) {
// YOUR CODE HERE:
// Return text with newlines inserted at word boundaries
}
// const longText = 'The quick brown fox jumps over the lazy dog.';
// console.log(wordWrap(longText, 15));
// 'The quick brown
// fox jumps over
// the lazy dog.'
/*
* SOLUTION:
*
* function wordWrap(text, maxLineLength) {
* const words = text.split(' ');
* const lines = [];
* let currentLine = '';
*
* for (const word of words) {
* if (currentLine.length + word.length + 1 <= maxLineLength) {
* currentLine += (currentLine ? ' ' : '') + word;
* } else {
* if (currentLine) lines.push(currentLine);
* currentLine = word;
* }
* }
* if (currentLine) lines.push(currentLine);
*
* return lines.join('\n');
* }
*/
/**
* EXERCISE 14: Slug Generator
*
* Convert a title to a URL-friendly slug.
*/
function generateSlug(title) {
// YOUR CODE HERE:
// Return lowercase slug with hyphens
}
// console.log(generateSlug('Hello World!')); // 'hello-world'
// console.log(generateSlug(' JavaScript Fundamentals ')); // 'javascript-fundamentals'
// console.log(generateSlug("It's a Test!!")); // 'its-a-test'
/*
* SOLUTION:
*
* function generateSlug(title) {
* return title
* .toLowerCase()
* .trim()
* .replace(/[^\w\s-]/g, '') // Remove special chars
* .replace(/\s+/g, '-') // Replace spaces with hyphens
* .replace(/-+/g, '-'); // Remove multiple hyphens
* }
*/
/**
* EXERCISE 15: Anagram Checker
*
* Check if two strings are anagrams.
*/
function areAnagrams(str1, str2) {
// YOUR CODE HERE:
// Return true if strings are anagrams (ignore case and spaces)
}
// console.log(areAnagrams('listen', 'silent')); // true
// console.log(areAnagrams('Hello', 'World')); // false
// console.log(areAnagrams('Astronomer', 'Moon starer')); // true
/*
* SOLUTION:
*
* function areAnagrams(str1, str2) {
* const normalize = str => str
* .toLowerCase()
* .replace(/[^a-z]/g, '')
* .split('')
* .sort()
* .join('');
*
* return normalize(str1) === normalize(str2);
* }
*/
/**
* EXERCISE 16: Compress String (Run-Length Encoding)
*
* Compress consecutive repeated characters.
*/
function compressString(str) {
// YOUR CODE HERE:
// Return compressed string
}
// console.log(compressString('aabbbcccc')); // 'a2b3c4'
// console.log(compressString('abcd')); // 'abcd' (no compression needed)
// console.log(compressString('aaAAbbBB')); // 'a2A2b2B2'
/*
* SOLUTION:
*
* function compressString(str) {
* let result = '';
* let count = 1;
*
* for (let i = 0; i < str.length; i++) {
* if (str[i] === str[i + 1]) {
* count++;
* } else {
* result += str[i] + (count > 1 ? count : '');
* count = 1;
* }
* }
*
* return result;
* }
*/
/**
* EXERCISE 17: Longest Common Prefix
*
* Find the longest common prefix of an array of strings.
*/
function longestCommonPrefix(strings) {
// YOUR CODE HERE:
// Return the common prefix
}
// console.log(longestCommonPrefix(['flower', 'flow', 'flight'])); // 'fl'
// console.log(longestCommonPrefix(['dog', 'racecar', 'car'])); // ''
// console.log(longestCommonPrefix(['test', 'testing', 'tester'])); // 'test'
/*
* SOLUTION:
*
* function longestCommonPrefix(strings) {
* if (strings.length === 0) return '';
*
* let prefix = strings[0];
*
* for (let i = 1; i < strings.length; i++) {
* while (!strings[i].startsWith(prefix)) {
* prefix = prefix.slice(0, -1);
* if (prefix === '') return '';
* }
* }
*
* return prefix;
* }
*/
/**
* EXERCISE 18: Highlight Search Term
*
* Wrap occurrences of a search term with HTML tags.
*/
function highlightSearch(text, term, tag = 'mark') {
// YOUR CODE HERE:
// Return text with term wrapped in tags (case-insensitive)
}
// console.log(highlightSearch('Hello World', 'world'));
// 'Hello <mark>World</mark>'
// console.log(highlightSearch('The quick brown fox', 'THE', 'strong'));
// '<strong>The</strong> quick brown fox'
/*
* SOLUTION:
*
* function highlightSearch(text, term, tag = 'mark') {
* const regex = new RegExp(`(${term})`, 'gi');
* return text.replace(regex, `<${tag}>$1</${tag}>`);
* }
*/
/**
* EXERCISE 19: String Interleave
*
* Interleave two strings character by character.
*/
function interleave(str1, str2) {
// YOUR CODE HERE:
// Return interleaved string
}
// console.log(interleave('abc', '123')); // 'a1b2c3'
// console.log(interleave('ab', '1234')); // 'a1b234'
// console.log(interleave('abcd', '12')); // 'a1b2cd'
/*
* SOLUTION:
*
* function interleave(str1, str2) {
* const maxLen = Math.max(str1.length, str2.length);
* let result = '';
*
* for (let i = 0; i < maxLen; i++) {
* if (i < str1.length) result += str1[i];
* if (i < str2.length) result += str2[i];
* }
*
* return result;
* }
*/
/**
* EXERCISE 20: String Difference
*
* Find what was added and removed between two versions.
*/
function stringDiff(original, modified) {
// YOUR CODE HERE:
// Return { added, removed } (as arrays of words)
}
// console.log(stringDiff('hello world', 'hello there'));
// { added: ['there'], removed: ['world'] }
/*
* SOLUTION:
*
* function stringDiff(original, modified) {
* const originalWords = new Set(original.split(/\s+/));
* const modifiedWords = new Set(modified.split(/\s+/));
*
* const added = [...modifiedWords].filter(w => !originalWords.has(w));
* const removed = [...originalWords].filter(w => !modifiedWords.has(w));
*
* return { added, removed };
* }
*/
console.log('String fundamentals exercises loaded!');