Web TypeScript 字符串处理示例
Web TypeScript 字符串处理示例,包括字符串操作、模式匹配和文本转换
💻 字符串分割和连接 typescript
🟢 simple
⭐⭐
将字符串分割为数组,并将数组连接为字符串,使用各种分隔符和定界符
⏱️ 25 min
🏷️ typescript, web, string processing
Prerequisites:
Basic TypeScript
// Web TypeScript String Split and Join Examples
// Splitting strings into arrays and joining arrays back into strings
// 1. Basic String Splitting
class StringSplitter {
// Split by single character
static splitByChar(text: string, delimiter: string): string[] {
return text.split(delimiter);
}
// Split by whitespace
static splitByWhitespace(text: string): string[] {
return text.split(/\s+/);
}
// Split into words (handles multiple spaces)
static splitIntoWords(text: string): string[] {
return text.trim().split(/\s+/).filter(word => word.length > 0);
}
// Split by line
static splitByLine(text: string): string[] {
return text.split(/\r?\n/);
}
// Split by length
static splitByLength(text: string, length: number): string[] {
const result: string[] = [];
for (let i = 0; i < text.length; i += length) {
result.push(text.slice(i, i + length));
}
return result;
}
// Split by multiple delimiters
static splitByMultiple(text: string, delimiters: string[]): string[] {
let result = text;
for (const delimiter of delimiters) {
result = result.split(delimiter).join(' ');
}
return result.split(/\s+/).filter(part => part.length > 0);
}
// Split keeping delimiters
static splitKeepingDelimiters(text: string, delimiter: string): string[] {
const parts: string[] = [];
let lastIndex = 0;
let index;
while ((index = text.indexOf(delimiter, lastIndex)) !== -1) {
parts.push(text.slice(lastIndex, index));
parts.push(delimiter);
lastIndex = index + delimiter.length;
}
parts.push(text.slice(lastIndex));
return parts;
}
// Split and trim
static splitAndTrim(text: string, delimiter: string): string[] {
return text.split(delimiter).map(part => part.trim()).filter(part => part.length > 0);
}
// Split into chunks of balanced parentheses
static splitBalanced(text: string, open: string, close: string): string[] {
const chunks: string[] = [];
let current = '';
let depth = 0;
for (const char of text) {
if (char === open) {
depth++;
current += char;
} else if (char === close) {
depth--;
current += char;
if (depth === 0 && current.length > 0) {
chunks.push(current);
current = '';
}
} else {
if (depth > 0) {
current += char;
}
}
}
if (current.length > 0) {
chunks.push(current);
}
return chunks;
}
}
// 2. Advanced String Joining
class StringJoiner {
// Join with separator
static join(parts: string[], separator: string): string {
return parts.join(separator);
}
// Join with new line
static joinWithNewLine(parts: string[]): string {
return parts.join('\n');
}
// Join with comma and space
static joinWithComma(parts: string[]): string {
return parts.join(', ');
}
// Join with custom prefix/suffix
static joinWithWrapper(parts: string[], separator: string, prefix: string, suffix: string): string {
return prefix + parts.join(separator) + suffix;
}
// Join with conditional separator
static joinConditional(parts: string[], separator: string): string {
return parts.filter(part => part !== null && part !== undefined && part.length > 0)
.join(separator);
}
// Join and limit
static joinWithLimit(parts: string[], separator: string, max: number, suffix: string = '...'): string {
if (parts.length <= max) {
return parts.join(separator);
}
return parts.slice(0, max).join(separator) + suffix;
}
// Join with last separator different
static joinWithOxfordComma(parts: string[]): string {
if (parts.length === 0) return '';
if (parts.length === 1) return parts[0];
if (parts.length === 2) return parts.join(' and ');
return parts.slice(0, -1).join(', ') + ', and ' + parts[parts.length - 1];
}
// Join with numbering
static joinWithNumbering(parts: string[], separator: string): string {
return parts.map((part, index) => `${index + 1}. ${part}`).join(separator);
}
}
// 3. String Tokenizer
class StringTokenizer {
private tokens: string[] = [];
private index: number = 0;
constructor(input: string, delimiters: string = ' \t\n\r') {
this.tokens = this.tokenize(input, delimiters);
}
private tokenize(input: string, delimiters: string): string[] {
const result: string[] = [];
let current = '';
for (const char of input) {
if (delimiters.includes(char)) {
if (current.length > 0) {
result.push(current);
current = '';
}
} else {
current += char;
}
}
if (current.length > 0) {
result.push(current);
}
return result;
}
hasMoreTokens(): boolean {
return this.index < this.tokens.length;
}
nextToken(): string | null {
if (this.hasMoreTokens()) {
return this.tokens[this.index++];
}
return null;
}
countTokens(): number {
return this.tokens.length - this.index;
}
getAllTokens(): string[] {
return [...this.tokens];
}
reset(): void {
this.index = 0;
}
}
// 4. String Builder
class StringBuilder {
private parts: string[] = [];
// Append string
append(text: string): this {
this.parts.push(text);
return this;
}
// Append line
appendLine(text: string): this {
this.parts.push(text);
this.parts.push('\n');
return this;
}
// Append multiple strings
appendAll(...texts: string[]): this {
this.parts.push(...texts);
return this;
}
// Clear builder
clear(): this {
this.parts = [];
return this;
}
// Get length
get length(): number {
return this.parts.join('').length;
}
// Check if empty
isEmpty(): boolean {
return this.parts.length === 0 || this.parts.every(p => p.length === 0);
}
// Build final string
toString(): string {
return this.parts.join('');
}
// Build with separator
join(separator: string): string {
return this.parts.join(separator);
}
}
// 5. Template Engine (Basic)
class TemplateEngine {
// Simple variable substitution
static render(template: string, data: Record<string, any>): string {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] !== undefined ? String(data[key]) : match;
});
}
// Template with conditionals
static renderWithConditionals(
template: string,
data: Record<string, any>
): string {
let result = template;
// Handle {{#if var}}...{{/if}}
result = result.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, varName, content) => {
return data[varName] ? content : '';
});
// Handle {{#unless var}}...{{/unless}}
result = result.replace(/\{\{#unless\s+(\w+)\}\}([\s\S]*?)\{\{\/unless\}\}/g, (match, varName, content) => {
return !data[varName] ? content : '';
});
// Replace variables
return this.render(result, data);
}
// Template with loops
static renderWithLoops(
template: string,
data: Record<string, any>
): string {
let result = template;
// Handle {{#each items}}...{{/each}}
result = result.replace(
/\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g,
(match, varName, itemTemplate) => {
const items = data[varName] as any[];
if (!Array.isArray(items)) return '';
return items.map((item, index) => {
let rendered = itemTemplate;
// Replace {{this}} with current item
rendered = rendered.replace(/\{\{this\}\}/g, String(item));
// Replace {{@index}} with current index
rendered = rendered.replace(/\{\{@index\}\}/g, String(index));
return rendered;
}).join('');
}
);
return this.render(result, data);
}
}
// 6. Text Formatter
class TextFormatter {
// Capitalize first letter
static capitalize(text: string): string {
if (text.length === 0) return text;
return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
}
// Capitalize each word
static capitalizeWords(text: string): string {
return text.split(/\s+/).map(word => this.capitalize(word)).join(' ');
}
// Convert to title case
static toTitleCase(text: string): string {
const minorWords = ['a', 'an', 'the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by'];
return text.split(/\s+/).map((word, index) => {
const lowerWord = word.toLowerCase();
if (index === 0 || !minorWords.includes(lowerWord)) {
return this.capitalize(lowerWord);
}
return lowerWord;
}).join(' ');
}
// Convert to camel case
static toCamelCase(text: string): string {
return text.split(/[_\s-]+/)
.map((word, index) => {
if (index === 0) {
return word.toLowerCase();
}
return this.capitalize(word.toLowerCase());
})
.join('');
}
// Convert to snake case
static toSnakeCase(text: string): string {
return text.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
}
// Convert to kebab case
static toKebabCase(text: string): string {
return text.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
}
// Truncate text
static truncate(text: string, maxLength: number, suffix: string = '...'): string {
if (text.length <= maxLength) {
return text;
}
return text.slice(0, maxLength - suffix.length) + suffix;
}
// Truncate words
static truncateWords(text: string, maxWords: number, suffix: string = '...'): string {
const words = text.split(/\s+/);
if (words.length <= maxWords) {
return text;
}
return words.slice(0, maxWords).join(' ') + suffix;
}
// Reverse string
static reverse(text: string): string {
return text.split('').reverse().join('');
}
// Shuffle words
static shuffleWords(text: string): string {
const words = text.split(/\s+/);
const shuffled = [...words].sort(() => Math.random() - 0.5);
return shuffled.join(' ');
}
// Justify text (add spaces to make each line the same width)
static justify(text: string, lineWidth: number): string {
const words = text.split(/\s+/);
const lines: string[] = [];
let currentLine: string[] = [];
let currentLength = 0;
for (const word of words) {
if (currentLength + word.length + currentLine.length > lineWidth) {
lines.push(currentLine.join(' '));
currentLine = [];
currentLength = 0;
}
currentLine.push(word);
currentLength += word.length;
}
if (currentLine.length > 0) {
lines.push(currentLine.join(' '));
}
return lines.join('\n');
}
}
// 7. String Encoding/Decoding
class StringEncoder {
// Base64 encode
static toBase64(text: string): string {
return btoa(unescape(encodeURIComponent(text)));
}
// Base64 decode
static fromBase64(base64: string): string {
return decodeURIComponent(escape(atob(base64)));
}
// URL encode
static encodeURL(text: string): string {
return encodeURIComponent(text);
}
// URL decode
static decodeURL(text: string): string {
return decodeURIComponent(text);
}
// HTML encode
static encodeHTML(text: string): string {
const htmlEntities: Record<string, string> = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, char => htmlEntities[char]);
}
// HTML decode
static decodeHTML(text: string): string {
const htmlEntities: Record<string, string> = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
''': "'"
};
return text.replace(/&|<|>|"|'/g, entity => htmlEntities[entity]);
}
}
// 8. String Analyzer
class StringAnalyzer {
// Count characters
static countCharacters(text: string, includeSpaces: boolean = true): number {
if (includeSpaces) {
return text.length;
}
return text.replace(/\s/g, '').length;
}
// Count words
static countWords(text: string): number {
return text.trim().split(/\s+/).filter(word => word.length > 0).length;
}
// Count lines
static countLines(text: string): number {
return text.split(/\r?\n/).length;
}
// Count paragraphs
static countParagraphs(text: string): number {
return text.split(/\n\s*\n/).filter(para => para.trim().length > 0).length;
}
// Get character frequency
static characterFrequency(text: string, caseSensitive: boolean = false): Map<string, number> {
const processed = caseSensitive ? text : text.toLowerCase();
const freq = new Map<string, number>();
for (const char of processed) {
if (char.match(/\w/)) {
freq.set(char, (freq.get(char) || 0) + 1);
}
}
return freq;
}
// Get word frequency
static wordFrequency(text: string): Map<string, number> {
const words = text.toLowerCase().split(/\s+/);
const freq = new Map<string, number>();
for (const word of words) {
if (word.match(/\w+/)) {
freq.set(word, (freq.get(word) || 0) + 1);
}
}
return freq;
}
// Find longest word
static findLongestWord(text: string): string {
const words = text.split(/\s+/);
return words.reduce((longest, word) => word.length > longest.length ? word : longest, '');
}
// Find shortest word
static findShortestWord(text: string): string {
const words = text.split(/\s+/).filter(w => w.length > 0);
return words.reduce((shortest, word) => word.length < shortest.length ? word : shortest, words[0] || '');
}
// Average word length
static averageWordLength(text: string): number {
const words = text.split(/\s+/).filter(w => w.length > 0);
if (words.length === 0) return 0;
const totalLength = words.reduce((sum, word) => sum + word.length, 0);
return totalLength / words.length;
}
}
// Usage Examples
async function demonstrateStringSplitJoin() {
console.log('=== Web TypeScript String Split and Join Examples ===\n');
// 1. Basic splitting
console.log('--- 1. Basic Splitting ---');
const text = 'Hello World TypeScript Programming';
console.log(`Split by space: ${StringSplitter.splitByChar(text, ' ')}`);
console.log(`Split into words: ${StringSplitter.splitIntoWords(text)}`);
console.log(`Split by length (5): ${StringSplitter.splitByLength(text, 5)}`);
const multiline = 'Line 1\nLine 2\nLine 3';
console.log(`Split by line: ${StringSplitter.splitByLine(multiline)}`);
// 2. Advanced splitting
console.log('\n--- 2. Advanced Splitting ---');
const complex = 'one,two;three:four';
console.log(`Split by multiple: ${StringSplitter.splitByMultiple(complex, [',', ';', ':'])}`);
const csv = 'apple, banana, cherry, date';
console.log(`Split and trim: ${StringSplitter.splitAndTrim(csv, ',')}`);
// 3. Joining
console.log('\n--- 3. Joining ---');
const fruits = ['apple', 'banana', 'cherry'];
console.log(`Join with comma: ${StringJoiner.joinWithComma(fruits)}`);
console.log(`Join with comma and space: ${StringJoiner.join(fruits, ', ')}`);
console.log(`Join with new line: ${StringJoiner.joinWithNewLine(fruits)}`);
console.log(`Oxford comma: ${StringJoiner.joinWithOxfordComma(fruits)}`);
// 4. String builder
console.log('\n--- 4. String Builder ---');
const builder = new StringBuilder();
builder.append('Hello').append(' ').append('World').appendLine('!');
builder.append('This is TypeScript');
console.log(`Built string: ${builder.toString()}`);
console.log(`Length: ${builder.length}`);
// 5. Tokenizer
console.log('\n--- 5. Tokenizer ---');
const tokenizer = new StringTokenizer('This is a test string', ' ');
console.log('Tokens:');
while (tokenizer.hasMoreTokens()) {
console.log(` ${tokenizer.nextToken()}`);
}
// 6. Template engine
console.log('\n--- 6. Template Engine ---');
const template = 'Hello {{name}}, welcome to {{place}}!';
const data = { name: 'Alice', place: 'Wonderland' };
console.log(`Rendered: ${TemplateEngine.render(template, data)}`);
// 7. Text formatting
console.log('\n--- 7. Text Formatting ---');
console.log(`Capitalize: ${TextFormatter.capitalize('hello world')}`);
console.log(`Title case: ${TextFormatter.toTitleCase('the quick brown fox')}`);
console.log(`Camel case: ${TextFormatter.toCamelCase('hello_world_text')}`);
console.log(`Snake case: ${TextFormatter.toSnakeCase('helloWorldText')}`);
console.log(`Kebab case: ${TextFormatter.toKebabCase('helloWorldText')}`);
// 8. Encoding/Decoding
console.log('\n--- 8. Encoding/Decoding ---');
const original = 'Hello World!';
const encoded = StringEncoder.toBase64(original);
const decoded = StringEncoder.fromBase64(encoded);
console.log(`Original: ${original}`);
console.log(`Base64: ${encoded}`);
console.log(`Decoded: ${decoded}`);
// 9. String analyzer
console.log('\n--- 9. String Analyzer ---');
const longText = 'The quick brown fox jumps over the lazy dog. The dog was not amused!';
console.log(`Characters: ${StringAnalyzer.countCharacters(longText)}`);
console.log(`Characters (no spaces): ${StringAnalyzer.countCharacters(longText, false)}`);
console.log(`Words: ${StringAnalyzer.countWords(longText)}`);
console.log(`Lines: ${StringAnalyzer.countLines(longText)}`);
console.log(`Longest word: ${StringAnalyzer.findLongestWord(longText)}`);
console.log(`Shortest word: ${StringAnalyzer.findShortestWord(longText)}`);
console.log(`Average word length: ${StringAnalyzer.averageWordLength(longText).toFixed(2)}`);
console.log('\n=== All String Split and Join Examples Completed ===');
}
// Export classes
export { StringSplitter, StringJoiner, StringTokenizer, StringBuilder, TemplateEngine, TextFormatter, StringEncoder, StringAnalyzer };
export { demonstrateStringSplitJoin };
💻 字符串替换 typescript
🟢 simple
⭐⭐⭐
使用各种方法和策略替换、替换和转换字符串
⏱️ 25 min
🏷️ typescript, web, string processing, replace
Prerequisites:
Basic TypeScript
// Web TypeScript String Replace Examples
// Comprehensive string replacement and transformation techniques
// 1. Basic String Replacement
class StringReplacer {
// Replace first occurrence
static replaceFirst(text: string, search: string, replacement: string): string {
return text.replace(search, replacement);
}
// Replace all occurrences
static replaceAll(text: string, search: string, replacement: string): string {
return text.split(search).join(replacement);
}
// Replace all (case insensitive)
static replaceAllIgnoreCase(text: string, search: string, replacement: string): string {
const regex = new RegExp(search, 'gi');
return text.replace(regex, replacement);
}
// Replace at index
static replaceAt(text: string, index: number, length: number, replacement: string): string {
return text.slice(0, index) + replacement + text.slice(index + length);
}
// Replace between indices
static replaceBetween(text: string, start: number, end: number, replacement: string): string {
return text.slice(0, start) + replacement + text.slice(end);
}
}
// 2. Advanced String Replacement
class AdvancedReplacer {
// Replace using callback function
static replaceWithFunction(
text: string,
pattern: string | RegExp,
callback: (match: string, ...groups: string[]) => string
): string {
return text.replace(pattern, callback);
}
// Replace multiple values at once
static replaceMultiple(
text: string,
replacements: Record<string, string>
): string {
let result = text;
for (const [search, replacement] of Object.entries(replacements)) {
result = result.split(search).join(replacement);
}
return result;
}
// Replace with template
static replaceWithTemplate(
text: string,
pattern: string | RegExp,
template: string
): string {
return text.replace(pattern, template);
}
// Replace preserving case
static replacePreservingCase(text: string, search: string, replacement: string): string {
return text.replace(new RegExp(search, 'gi'), (match) => {
if (match === match.toUpperCase()) {
return replacement.toUpperCase();
} else if (match === match.toLowerCase()) {
return replacement.toLowerCase();
} else if (match[0] === match[0].toUpperCase()) {
return replacement.charAt(0).toUpperCase() + replacement.slice(1).toLowerCase();
}
return replacement;
});
}
// Replace nth occurrence
static replaceNth(
text: string,
search: string,
replacement: string,
n: number
): string {
const parts = text.split(search);
if (n < 0 || n >= parts.length - 1) {
return text;
}
parts[n] = replacement;
return parts.join(search);
}
// Replace first and last
static replaceFirstAndLast(
text: string,
search: string,
replacement: string
): string {
const parts = text.split(search);
if (parts.length <= 1) {
return text;
}
parts[0] = replacement;
parts[parts.length - 1] = replacement;
return parts.join(search);
}
}
// 3. Pattern-Based Replacement
class PatternReplacer {
// Replace using regex
static replaceWithRegex(
text: string,
pattern: RegExp,
replacement: string
): string {
return text.replace(pattern, replacement);
}
// Replace words
static replaceWords(
text: string,
words: string[],
replacement: string
): string {
const pattern = new RegExp(`\\b(${words.join('|')})\\b`, 'gi');
return text.replace(pattern, replacement);
}
// Replace vowels
static replaceVowels(text: string, replacement: string): string {
return text.replace(/[aeiou]/gi, replacement);
}
// Replace consonants
static replaceConsonants(text: string, replacement: string): string {
return text.replace(/[^aeiou\s]/gi, replacement);
}
// Replace digits
static replaceDigits(text: string, replacement: string): string {
return text.replace(/\d/g, replacement);
}
// Replace whitespace
static replaceWhitespace(text: string, replacement: string): string {
return text.replace(/\s+/g, replacement);
}
// Replace line breaks
static replaceLineBreaks(text: string, replacement: string): string {
return text.replace(/\r?\n/g, replacement);
}
}
// 4. Text Transformation
class TextTransformer {
// To uppercase
static toUpperCase(text: string): string {
return text.toUpperCase();
}
// To lowercase
static toLowerCase(text: string): string {
return text.toLowerCase();
}
// To title case
static toTitleCase(text: string): string {
return text.replace(/\w\S*/g, (word) => {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
});
}
// To sentence case
static toSentenceCase(text: string): string {
return text.toLowerCase().replace(/(\.\s*)([a-z])/g, (_, prefix, letter) => {
return prefix + letter.toUpperCase();
});
}
// To alternating case
static toAlternatingCase(text: string): string {
return text.split('').map((char, index) => {
return index % 2 === 0 ? char.toUpperCase() : char.toLowerCase();
}).join('');
}
// To inverse case
static toInverseCase(text: string): string {
return text.split('').map(char => {
return char === char.toUpperCase() ? char.toLowerCase() : char.toUpperCase();
}).join('');
}
// Capitalize first letter
static capitalize(text: string): string {
return text.charAt(0).toUpperCase() + text.slice(1);
}
// Capitalize all words
static capitalizeWords(text: string): string {
return text.replace(/\b\w/g, char => char.toUpperCase());
}
}
// 5. String Template Replacement
class TemplateReplacer {
// Replace {{variable}} placeholders
static replaceVariables(
template: string,
variables: Record<string, any>
): string {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return variables[key] !== undefined ? String(variables[key]) : match;
});
}
// Replace ${variable} placeholders
static replaceES6Variables(
template: string,
variables: Record<string, any>
): string {
return template.replace(/\$\{(\w+)\}/g, (match, key) => {
return variables[key] !== undefined ? String(variables[key]) : match;
});
}
// Replace %s placeholders (printf style)
static replacePrintfStyle(template: string, ...values: any[]): string {
let index = 0;
return template.replace(/%s/g, () => {
return index < values.length ? String(values[index++]) : '%s';
});
}
// Replace ? placeholders (SQL style)
static replaceQuestionMarks(template: string, ...values: any[]): string {
let index = 0;
return template.replace(/\?/g, () => {
return index < values.length ? String(values[index++]) : '?';
});
}
// Replace with numbered placeholders {0}, {1}, etc.
static replaceNumbered(template: string, ...values: any[]): string {
return template.replace(/\{(\d+)\}/g, (match, index) => {
const i = parseInt(index);
return i < values.length ? String(values[i]) : match;
});
}
}
// 6. Masking and Censoring
class StringMasker {
// Mask email
static maskEmail(email: string): string {
const [username, domain] = email.split('@');
if (username.length <= 2) {
return `${username[0]}***@${domain}`;
}
return `${username[0]}${'*'.repeat(username.length - 2)}${username[username.length - 1]}@${domain}`;
}
// Mask phone number
static maskPhone(phone: string): string {
const cleaned = phone.replace(/\D/g, '');
if (cleaned.length < 4) {
return '*'.repeat(cleaned.length);
}
return cleaned.slice(0, -4).replace(/\d/g, '*') + cleaned.slice(-4);
}
// Mask credit card
static maskCreditCard(card: string): string {
const cleaned = card.replace(/\s/g, '');
if (cleaned.length < 4) {
return cleaned;
}
return '*'.repeat(cleaned.length - 4) + cleaned.slice(-4);
}
// Mask string partially
static maskPartial(text: string, visibleStart: number = 2, visibleEnd: number = 2): string {
if (text.length <= visibleStart + visibleEnd) {
return text;
}
return text.slice(0, visibleStart) +
'*'.repeat(text.length - visibleStart - visibleEnd) +
text.slice(-visibleEnd);
}
// Censor words
static censorWords(text: string, words: string[], censorChar: string = '*'): string {
const pattern = new RegExp(`\\b(${words.join('|')})\\b`, 'gi');
return text.replace(pattern, (match) => {
return censorChar.repeat(match.length);
});
}
// Censor profanity
static censorProfanity(text: string, censorChar: string = '*'): string {
const profanityList = ['damn', 'hell', 'shit', 'fuck']; // Add more as needed
return this.censorWords(text, profanityList, censorChar);
}
}
// 7. String Cleanup
class StringCleaner {
// Trim whitespace
static trim(text: string): string {
return text.trim();
}
// Trim left
static trimLeft(text: string): string {
return text.trimLeft();
}
// Trim right
static trimRight(text: string): string {
return text.trimRight();
}
// Remove extra spaces
static collapseWhitespace(text: string): string {
return text.replace(/\s+/g, ' ').trim();
}
// Remove all whitespace
static removeAllWhitespace(text: string): string {
return text.replace(/\s/g, '');
}
// Remove line breaks
static removeLineBreaks(text: string): string {
return text.replace(/\r?\n/g, ' ');
}
// Remove punctuation
static removePunctuation(text: string): string {
return text.replace(/[.,\/#!$%^&*;:{}=\-_`~()]/g, '');
}
// Remove special characters
static removeSpecialChars(text: string): string {
return text.replace(/[^a-zA-Z0-9\s]/g, '');
}
// Remove duplicate characters
static removeDuplicateChars(text: string): string {
return text.split('').filter((char, index, self) => {
return self.indexOf(char) === index;
}).join('');
}
// Remove duplicate words
static removeDuplicateWords(text: string): string {
return text.replace(/\b(\w+)\b(\s+\1\b)+/gi, '$1');
}
}
// 8. String Normalization
class StringNormalizer {
// Normalize whitespace
static normalizeWhitespace(text: string): string {
return text.replace(/\s+/g, ' ').trim();
}
// Normalize line endings
static normalizeLineEndings(text: string, lineEnding: '\n' | '\r\n' = '\n'): string {
return text.replace(/\r?\n/g, lineEnding);
}
// Normalize case to lowercase
static normalizeToLower(text: string): string {
return text.toLowerCase();
}
// Normalize case to uppercase
static normalizeToUpper(text: string): string {
return text.toUpperCase();
}
// Normalize quotes
static normalizeQuotes(text: string): string {
return text
.replace(/[\u2018\u2019]/g, "'")
.replace(/[\u201C\u201D]/g, '"');
}
// Normalize dashes
static normalizeDashes(text: string): string {
return text.replace(/[\u2010-\u2015\u2212]/g, '-');
}
// Normalize accented characters
static normalizeAccents(text: string): string {
return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
}
// Usage Examples
async function demonstrateStringReplace() {
console.log('=== Web TypeScript String Replace Examples ===\n');
// 1. Basic replacement
console.log('--- 1. Basic Replacement ---');
const text = 'Hello World! World is beautiful.';
console.log(`Original: ${text}`);
console.log(`Replace first 'World': ${StringReplacer.replaceFirst(text, 'World', 'Earth')}`);
console.log(`Replace all 'World': ${StringReplacer.replaceAll(text, 'World', 'Earth')}`);
console.log(`Replace all case insensitive: ${StringReplacer.replaceAllIgnoreCase(text, 'world', 'Earth')}`);
// 2. Advanced replacement
console.log('\n--- 2. Advanced Replacement ---');
const multiText = 'The quick brown fox jumps over the lazy dog.';
console.log(`Original: ${multiText}`);
const replaced = AdvancedReplacer.replaceMultiple(multiText, {
'quick': 'slow',
'brown': 'white',
'lazy': 'energetic'
});
console.log(`Replace multiple: ${replaced}`);
console.log(`Replace 2nd 'the': ${AdvancedReplacer.replaceNth(multiText.toLowerCase(), 'the', 'a', 2)}`);
console.log(`Replace preserving case: ${AdvancedReplacer.replacePreservingCase(multiText, 'the', 'a')}`);
// 3. Pattern-based replacement
console.log('\n--- 3. Pattern-Based Replacement ---');
const patternText = 'Hello 123 World 456 Test 789';
console.log(`Original: ${patternText}`);
console.log(`Replace digits: ${PatternReplacer.replaceDigits(patternText, '#')}`);
console.log(`Replace words: ${PatternReplacer.replaceWords(patternText, ['Hello', 'World'], 'Hi')}`);
console.log(`Replace whitespace: ${PatternReplacer.replaceWhitespace(patternText, '-')}`);
// 4. Text transformation
console.log('\n--- 4. Text Transformation ---');
const transformText = 'hello world this is typescript';
console.log(`Original: ${transformText}`);
console.log(`Uppercase: ${TextTransformer.toUpperCase(transformText)}`);
console.log(`Lowercase: ${TextTransformer.toLowerCase(transformText)}`);
console.log(`Title case: ${TextTransformer.toTitleCase(transformText)}`);
console.log(`Sentence case: ${TextTransformer.toSentenceCase(transformText)}`);
console.log(`Alternating case: ${TextTransformer.toAlternatingCase('hello')}`);
console.log(`Inverse case: ${TextTransformer.toInverseCase('HeLLo WoRLd')}`);
// 5. Template replacement
console.log('\n--- 5. Template Replacement ---');
const template = 'Hello {{name}}, welcome to {{place}}! You have {{count}} messages.';
const variables = { name: 'Alice', place: 'Wonderland', count: 5 };
console.log(`Template: ${template}`);
console.log(`Replaced: ${TemplateReplacer.replaceVariables(template, variables)}`);
const printfTemplate = 'Hello %s, you are %s years old.';
console.log(`Printf style: ${TemplateReplacer.replacePrintfStyle(printfTemplate, 'Bob', 30)}`);
const numberedTemplate = 'Dear {0}, your order {1} is {2}.';
console.log(`Numbered: ${TemplateReplacer.replaceNumbered(numberedTemplate, 'John', '12345', 'ready')}`);
// 6. Masking
console.log('\n--- 6. Masking ---');
console.log(`Mask email: ${StringMasker.maskEmail('[email protected]')}`);
console.log(`Mask phone: ${StringMasker.maskPhone('(555) 123-4567')}`);
console.log(`Mask credit card: ${StringMasker.maskCreditCard('4532 1234 5678 9010')}`);
console.log(`Mask partial: ${StringMasker.maskPartial('SecretPassword', 2, 2)}`);
const censorText = 'This damn hell is really shitty';
console.log(`Censor: ${StringMasker.censorProfanity(censorText)}`);
// 7. Cleanup
console.log('\n--- 7. Cleanup ---');
const messy = ' This is a messy text \n with extra spaces ';
console.log(`Original: '${messy}'`);
console.log(`Trim: '${StringCleaner.trim(messy)}'`);
console.log(`Collapse whitespace: '${StringCleaner.collapseWhitespace(messy)}'`);
console.log(`Remove all whitespace: '${StringCleaner.removeAllWhitespace(messy)}'`);
console.log(`Remove line breaks: '${StringCleaner.removeLineBreaks(messy)}'`);
// 8. Normalization
console.log('\n--- 8. Normalization ---');
const unnormalized = 'Hello World!\n\rThis is a test.\n';
console.log(`Original: '${unnormalized}'`);
console.log(`Normalized whitespace: '${StringNormalizer.normalizeWhitespace(unnormalized)}'`);
console.log(`Normalized line endings: '${StringNormalizer.normalizeLineEndings(unnormalized)}'`);
const quotes = 'Hello "world" and 'goodbye'';
console.log(`Normalize quotes: ${StringNormalizer.normalizeQuotes(quotes)}`);
const accented = 'café résumé';
console.log(`Normalize accents: ${StringNormalizer.normalizeAccents(accented)}`);
console.log('\n=== All String Replace Examples Completed ===');
}
// Export classes
export { StringReplacer, AdvancedReplacer, PatternReplacer, TextTransformer, TemplateReplacer, StringMasker, StringCleaner, StringNormalizer };
export { demonstrateStringReplace };
💻 正则表达式 typescript
🟡 intermediate
⭐⭐⭐
使用正则表达式进行模式匹配、验证、搜索和文本替换
⏱️ 30 min
🏷️ typescript, web, string processing, regex
Prerequisites:
Intermediate TypeScript, Regular Expressions
// Web TypeScript Regular Expressions Examples
// Pattern matching, validation, searching, and text replacement with regex
// 1. Pattern Matching
class PatternMatcher {
// Check if pattern matches
static test(text: string, pattern: string): boolean {
const regex = new RegExp(pattern);
return regex.test(text);
}
// Find all matches
static findAll(text: string, pattern: string, flags: string = 'g'): RegExpMatchArray | null {
const regex = new RegExp(pattern, flags);
return text.match(regex);
}
// Find first match
static findFirst(text: string, pattern: string): RegExpExecArray | null {
const regex = new RegExp(pattern);
return regex.exec(text);
}
// Extract groups from match
static extractGroups(text: string, pattern: string): Record<string, string> | null {
const regex = new RegExp(pattern);
const match = regex.exec(text);
if (!match) return null;
const groups: Record<string, string> = {};
if (match.groups) {
for (const [key, value] of Object.entries(match.groups)) {
groups[key] = value;
}
}
return groups;
}
// Match all with capturing groups
static matchWithGroups(text: string, pattern: string): Array<Record<string, string>> {
const regex = new RegExp(pattern, 'g');
const results: Array<Record<string, string>> = [];
let match;
while ((match = regex.exec(text)) !== null) {
const groups: Record<string, string> = {};
if (match.groups) {
for (const [key, value] of Object.entries(match.groups)) {
groups[key] = value;
}
}
results.push(groups);
}
return results;
}
// Check if string matches pattern entirely
static matchesEntirely(text: string, pattern: string): boolean {
const regex = new RegExp(`^${pattern}$`);
return regex.test(text);
}
}
// 2. Common Validators
class Validators {
// Email validation
static isValidEmail(email: string): boolean {
const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return pattern.test(email);
}
// URL validation
static isValidURL(url: string): boolean {
const pattern = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)?$/;
return pattern.test(url);
}
// Phone number validation (US format)
static isValidPhone(phone: string): boolean {
const pattern = /^\+?(\d{1,3})?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
return pattern.test(phone);
}
// IP address validation (IPv4)
static isValidIPv4(ip: string): boolean {
const pattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return pattern.test(ip);
}
// Date validation (YYYY-MM-DD)
static isValidDate(date: string): boolean {
const pattern = /^(\d{4})-(\d{2})-(\d{2})$/;
if (!pattern.test(date)) return false;
const [, year, month, day] = date.match(pattern)!;
const dateObj = new Date(`${year}-${month}-${day}`);
return dateObj.getFullYear() === parseInt(year) &&
dateObj.getMonth() === parseInt(month) - 1 &&
dateObj.getDate() === parseInt(day);
}
// Credit card validation (Luhn algorithm)
static isValidCreditCard(cardNumber: string): boolean {
const cleaned = cardNumber.replace(/\s+/g, '');
if (!/^\d{13,19}$/.test(cleaned)) return false;
let sum = 0;
let isEven = false;
for (let i = cleaned.length - 1; i >= 0; i--) {
let digit = parseInt(cleaned[i]);
if (isEven) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
isEven = !isEven;
}
return sum % 10 === 0;
}
// Username validation
static isValidUsername(username: string): boolean {
const pattern = /^[a-zA-Z0-9_]{3,16}$/;
return pattern.test(username);
}
// Password strength validation
static getPasswordStrength(password: string): 'weak' | 'medium' | 'strong' {
if (password.length < 8) return 'weak';
let score = 0;
if (/[a-z]/.test(password)) score++;
if (/[A-Z]/.test(password)) score++;
if (/[0-9]/.test(password)) score++;
if (/[^a-zA-Z0-9]/.test(password)) score++;
if (score <= 2) return 'weak';
if (score === 3) return 'medium';
return 'strong';
}
// Hex color validation
static isValidHexColor(color: string): boolean {
const pattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
return pattern.test(color);
}
}
// 3. Text Search with Regex
class RegexSearcher {
// Find all occurrences of pattern
static findAll(text: string, pattern: string): { match: string; index: number }[] {
const regex = new RegExp(pattern, 'gi');
const results: { match: string; index: number }[] = [];
let match;
while ((match = regex.exec(text)) !== null) {
results.push({
match: match[0],
index: match.index
});
}
return results;
}
// Find words matching pattern
static findWords(text: string, pattern: string): string[] {
const regex = new RegExp(`\\b${pattern}\\b`, 'gi');
const matches = text.match(regex);
return matches ? Array.from(new Set(matches.map(m => m.toLowerCase()))) : [];
}
// Find sentences containing pattern
static findSentences(text: string, pattern: string): string[] {
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
const regex = new RegExp(pattern, 'gi');
return sentences.filter(sentence => regex.test(sentence));
}
// Context search (find pattern with surrounding text)
static findWithContext(text: string, pattern: string, contextChars: number = 20): Array<{
match: string;
context: string;
index: number;
}> {
const regex = new RegExp(pattern, 'gi');
const results: Array<{ match: string; context: string; index: number }> = [];
let match;
while ((match = regex.exec(text)) !== null) {
const start = Math.max(0, match.index - contextChars);
const end = Math.min(text.length, match.index + match[0].length + contextChars);
results.push({
match: match[0],
context: text.slice(start, end),
index: match.index
});
}
return results;
}
}
// 4. Text Replacement with Regex
class RegexReplacer {
// Replace all occurrences
static replaceAll(text: string, pattern: string, replacement: string): string {
const regex = new RegExp(pattern, 'g');
return text.replace(regex, replacement);
}
// Replace with function
static replaceWithFunction(
text: string,
pattern: string,
replacer: (match: string, ...groups: string[]) => string
): string {
const regex = new RegExp(pattern, 'g');
return text.replace(regex, replacer);
}
// Replace but preserve case
static replacePreservingCase(text: string, pattern: string, replacement: string): string {
return text.replace(new RegExp(pattern, 'gi'), (match) => {
if (match === match.toUpperCase()) {
return replacement.toUpperCase();
} else if (match === match.toLowerCase()) {
return replacement.toLowerCase();
} else if (match[0] === match[0].toUpperCase()) {
return replacement.charAt(0).toUpperCase() + replacement.slice(1).toLowerCase();
}
return replacement;
});
}
// Remove all matches
static removeAll(text: string, pattern: string): string {
const regex = new RegExp(pattern, 'g');
return text.replace(regex, '');
}
// Remove duplicate words
static removeDuplicateWords(text: string): string {
return text.replace(/\b(\w+)\b(\s+\1\b)+/gi, '$1');
}
// Remove extra whitespace
static normalizeWhitespace(text: string): string {
return text.replace(/\s+/g, ' ').trim();
}
}
// 5. Text Extraction
class TextExtractor {
// Extract email addresses
static extractEmails(text: string): string[] {
const pattern = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
const matches = text.match(pattern);
return matches ? Array.from(new Set(matches)) : [];
}
// Extract URLs
static extractURLs(text: string): string[] {
const pattern = /https?:\/\/[^\s<>"{}|\\^\[\]]+/g;
const matches = text.match(pattern);
return matches ? Array.from(new Set(matches)) : [];
}
// Extract hashtags
static extractHashtags(text: string): string[] {
const pattern = /#\w+/g;
const matches = text.match(pattern);
return matches || [];
}
// Extract mentions
static extractMentions(text: string): string[] {
const pattern = /@\w+/g;
const matches = text.match(pattern);
return matches || [];
}
// Extract numbers
static extractNumbers(text: string): number[] {
const pattern = /-?\d+(\.\d+)?/g;
const matches = text.match(pattern);
return matches ? matches.map(m => parseFloat(m)) : [];
}
// Extract dates (YYYY-MM-DD format)
static extractDates(text: string): string[] {
const pattern = /\d{4}-\d{2}-\d{2}/g;
const matches = text.match(pattern);
return matches || [];
}
// Extract phone numbers
static extractPhones(text: string): string[] {
const pattern = /\+?\d{1,3}?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
const matches = text.match(pattern);
return matches || [];
}
}
// 6. Text Sanitization
class TextSanitizer {
// Remove HTML tags
static stripHTMLTags(text: string): string {
return text.replace(/<[^>]*>/g, '');
}
// Escape HTML
static escapeHTML(text: string): string {
const htmlEntities: Record<string, string> = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, char => htmlEntities[char]);
}
// Remove special characters
static removeSpecialChars(text: string, keepSpaces: boolean = true): string {
const pattern = keepSpaces ? /[^a-zA-Z0-9\s]/g : /[^a-zA-Z0-9]/g;
return text.replace(pattern, '');
}
// Remove accents
static removeAccents(text: string): string {
return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
// Sanitize filename
static sanitizeFilename(filename: string): string {
return filename.replace(/[^a-zA-Z0-9._-]/g, '_');
}
}
// 7. Regex Builder
class RegexBuilder {
private pattern: string = '';
private flags: string = '';
// Match literal
literal(text: string): this {
this.pattern += text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return this;
}
// Match any character
anyChar(): this {
this.pattern += '.';
return this;
}
// Match digit
digit(): this {
this.pattern += '\\d';
return this;
}
// Match word character
wordChar(): this {
this.pattern += '\\w';
return this;
}
// Match whitespace
whitespace(): this {
this.pattern += '\\s';
return this;
}
// Start of string
startOfLine(): this {
this.pattern += '^';
return this;
}
// End of string
endOfLine(): this {
this.pattern += '$';
return this;
}
// Match one or more
oneOrMore(): this {
this.pattern += '+';
return this;
}
// Match zero or more
zeroOrMore(): this {
this.pattern += '*';
return this;
}
// Match zero or one
zeroOrOne(): this {
this.pattern += '?';
return this;
}
// Match range
range(min: number, max?: number): this {
if (max === undefined) {
this.pattern += `{${min}}`;
} else {
this.pattern += `{${min},${max}}`;
}
return this;
}
// Any of
anyOf(...chars: string[]): this {
this.pattern += `[${chars.join('')}]`;
return this;
}
// Capture group
capture(): this {
this.pattern += '(';
return this;
}
// End capture group
endCapture(): this {
this.pattern += ')';
return this;
}
// Named capture group
namedCapture(name: string): this {
this.pattern += `(?<${name}>`;
return this;
}
// Or
or(): this {
this.pattern += '|';
return this;
}
// Set flags
setFlags(flags: string): this {
this.flags = flags;
return this;
}
// Build regex
build(): RegExp {
return new RegExp(this.pattern, this.flags);
}
// Get pattern string
getPattern(): string {
return this.pattern;
}
}
// Usage Examples
async function demonstrateRegularExpressions() {
console.log('=== Web TypeScript Regular Expressions Examples ===\n');
// 1. Pattern matching
console.log('--- 1. Pattern Matching ---');
const text = 'Contact us at [email protected] or [email protected]';
console.log(`Text: ${text}`);
console.log(`Has email pattern: ${PatternMatcher.test(text, '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}')}`);
const matches = PatternMatcher.findAll(text, '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}');
console.log(`Emails found: ${matches ? matches.join(', ') : 'none'}`);
// 2. Validators
console.log('\n--- 2. Validators ---');
console.log(`Valid email: ${Validators.isValidEmail('[email protected]')}`);
console.log(`Valid URL: ${Validators.isValidURL('https://www.example.com')}`);
console.log(`Valid phone: ${Validators.isValidPhone('(555) 123-4567')}`);
console.log(`Valid IPv4: ${Validators.isValidIPv4('192.168.1.1')}`);
console.log(`Valid date: ${Validators.isValidDate('2024-01-15')}`);
console.log(`Valid credit card: ${Validators.isValidCreditCard('4532 1234 5678 9010')}`);
console.log(`Valid username: ${Validators.isValidUsername('user_123')}`);
console.log(`Password strength: ${Validators.getPasswordStrength('Abc123!@')}`);
// 3. Regex search
console.log('\n--- 3. Regex Search ---');
const searchText = 'The quick brown fox jumps over the lazy dog. The fox is very fast.';
const occurrences = RegexSearcher.findAll(searchText, 'fox');
console.log(`'fox' occurrences: ${occurrences.length}`);
occurrences.forEach(occ => console.log(` Found at index ${occ.index}: ${occ.match}`));
const words = RegexSearcher.findWords(searchText, 'f.*');
console.log(`Words starting with 'f': ${words.join(', ')}`);
const withContext = RegexSearcher.findWithContext(searchText, 'fox', 15);
console.log('With context:');
withContext.forEach(ctx => console.log(` ... ${ctx.context} ...`));
// 4. Text replacement
console.log('\n--- 4. Text Replacement ---');
const originalText = 'Hello world, World is beautiful. WORLD is amazing.';
console.log(`Original: ${originalText}`);
console.log(`Replace all 'world': ${RegexReplacer.replaceAll(originalText, 'world', 'earth')}`);
console.log(`Replace preserving case: ${RegexReplacer.replacePreservingCase(originalText, 'world', 'earth')}`);
const messy = 'This is a messy text.';
console.log(`Normalize whitespace: ${RegexReplacer.normalizeWhitespace(messy)}`);
// 5. Text extraction
console.log('\n--- 5. Text Extraction ---');
const extractText = 'Contact us at [email protected] or visit https://example.com. Call +1-555-123-4567. #tech @user';
console.log(`Text: ${extractText}`);
console.log(`Emails: ${TextExtractor.extractEmails(extractText).join(', ')}`);
console.log(`URLs: ${TextExtractor.extractURLs(extractText).join(', ')}`);
console.log(`Hashtags: ${TextExtractor.extractHashtags(extractText).join(', ')}`);
console.log(`Mentions: ${TextExtractor.extractMentions(extractText).join(', ')}`);
console.log(`Phones: ${TextExtractor.extractPhones(extractText).join(', ')}`);
// 6. Text sanitization
console.log('\n--- 6. Text Sanitization ---');
const html = '<p>Hello <b>World</b>!</p>';
console.log(`Original: ${html}`);
console.log(`Strip HTML: ${TextSanitizer.stripHTMLTags(html)}`);
console.log(`Escape HTML: ${TextSanitizer.escapeHTML(html)}`);
const special = 'Hello, World! @#$ %^&*()';
console.log(`Remove special: ${TextSanitizer.removeSpecialChars(special)}`);
const accented = 'café résumé naïve';
console.log(`Remove accents: ${TextSanitizer.removeAccents(accented)}`);
const filename = 'my/file:name*.txt';
console.log(`Sanitize filename: ${TextSanitizer.sanitizeFilename(filename)}`);
// 7. Regex builder
console.log('\n--- 7. Regex Builder ---');
const emailRegex = new RegexBuilder()
.startOfLine()
.capture().wordChar().oneOrMore().endCapture()
.literal('@')
.capture().wordChar().oneOrMore().endCapture()
.literal('.')
.capture().wordChar().range(2, 4).endCapture()
.endOfLine()
.build();
console.log(`Built pattern: ${emailRegex.source}`);
console.log(`Test email: ${emailRegex.test('[email protected]')}`);
const numberRegex = new RegexBuilder()
.startOfLine()
.capture().digit().oneOrMore().endCapture()
.literal('.')
.capture().digit().range(2).endCapture()
.endOfLine()
.build();
console.log(`Price pattern: ${numberRegex.source}`);
console.log(`Test price: ${numberRegex.test('19.99')}`);
console.log('\n=== All Regular Expressions Examples Completed ===');
}
// Export classes
export { PatternMatcher, Validators, RegexSearcher, RegexReplacer, TextExtractor, TextSanitizer, RegexBuilder };
export { demonstrateRegularExpressions };