Exemples de Traitement de Chaînes Web TypeScript

Exemples de traitement de chaînes Web TypeScript incluant la manipulation de chaînes, le correspondance de modèles et la transformation de texte

Key Facts

Category
TypeScript
Items
3
Format Families
text, regex

Sample Overview

Exemples de traitement de chaînes Web TypeScript incluant la manipulation de chaînes, le correspondance de modèles et la transformation de texte This sample set belongs to TypeScript and can be used to test related workflows inside Elysia Tools.

💻 Diviser et Joindre des Chaînes typescript

🟢 simple ⭐⭐

Diviser les chaînes en tableaux et joindre les tableaux en chaînes avec divers séparateurs et délimiteurs

⏱️ 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> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#039;'
    };

    return text.replace(/[&<>"']/g, char => htmlEntities[char]);
  }

  // HTML decode
  static decodeHTML(text: string): string {
    const htmlEntities: Record<string, string> = {
      '&amp;': '&',
      '&lt;': '<',
      '&gt;': '>',
      '&quot;': '"',
      '&#039;': "'"
    };

    return text.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/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 };

💻 Remplacement de Chaînes typescript

🟢 simple ⭐⭐⭐

Remplacer, substituer et transformer des chaînes en utilisant diverses méthodes et stratégies

⏱️ 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 };

💻 Expressions Régulières typescript

🟡 intermediate ⭐⭐⭐

Utiliser des expressions régulières pour la correspondance de modèles, la validation, la recherche et le remplacement de texte

⏱️ 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> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#039;'
    };

    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 };