/stringkit-fp

Comprehensive string manipulation library providing 60+ static methods for validation, case conversion, pattern matching, fuzzy algorithms, phonetic matching, text analysis, and web encoding. Zero external dependencies - uses only Free Pascal RTL.

Primary LanguagePascalMIT LicenseMIT

๐Ÿงต StringKit-FP: The Complete String Toolkit

FPC Lazarus License Documentation Tests Status Version

StringKit-FP Logo

๐Ÿ“š Table of Contents

๐Ÿงต Why Choose StringKit-FP?

Professional string toolkit featuring advanced algorithms: Levenshtein/Jaro similarity, Soundex/Metaphone phonetics, readability scoring, regex patterns, HTML/URL encoding, and comprehensive validation. Static API, no instantiation required.

๐ŸŽฏ Key Advantages:

  • ๐Ÿงถ Comprehensive: 90+ string operations covering validation, transformation, analysis, and encoding
  • ๐Ÿชก Zero Dependencies: Uses only standard Free Pascal RTL - no external libraries required
  • ๐Ÿ“ Advanced Analysis: Readability scoring, n-gram generation, and statistical text analysis
  • ๐Ÿ” Robust Validation: Regex patterns, format checking, and custom validation rules
  • ๐ŸŒ Web-Ready: URL encoding, HTML escaping, and modern web standards support
  • ๐Ÿงช Thoroughly Tested: Comprehensive test suite ensuring reliability in production
  • โšก Simple API: Static methods - no object instantiation required, just call and use

โœจ Feature Overview

๐ŸŽญ Case Conversion & Formatting

Professional text styling and formatting

  • ToUpper(), ToLower(), ToTitleCase() - Standard case transformations
  • ToCamelCase(), ToPascalCase(), ToSnakeCase(), ToKebabCase() - Modern naming conventions
  • PadLeft(), PadRight(), PadCenter() - Text alignment with custom padding
  • Truncate() - Smart text truncation with ellipsis support
  • CapitalizeText() - Intelligent word capitalization

๐Ÿ” Validation & Pattern Matching

Robust string validation and pattern extraction

  • IsValidEmail(), IsValidURL(), IsValidIP() - Comprehensive format validation
  • IsValidDate() - Date validation with custom format support
  • MatchesPattern() - Powerful regex pattern matching
  • ExtractMatches(), ExtractAllMatches() - Extract matching substrings

๐Ÿงฌ Similarity & Fuzzy Matching

Advanced string comparison algorithms

  • LevenshteinDistance(), LevenshteinSimilarity() - Edit distance calculations
  • HammingDistance() - Character-by-character comparison for equal-length strings
  • JaroSimilarity(), JaroWinklerSimilarity() - Sophisticated similarity metrics
  • LongestCommonSubsequence(), LCSSimilarity() - Common subsequence analysis
  • IsFuzzyMatch() - Multi-algorithm fuzzy string matching

๐ŸŽต Phonetic Matching

Sound-based string comparison algorithms

  • Soundex() - Russell-Odell phonetic algorithm for name matching
  • Metaphone() - Advanced English pronunciation-based matching

๐Ÿ›๏ธ Number Formatting

Professional number and numeric string handling

  • ToRoman(), FromRoman() - Roman numeral conversion (1-3999)
  • FormatFileSize() - Human-readable file size formatting (B, KB, MB, GB, TB)
  • FormatNumber(), FormatFloat() - Thousand-separator formatting
  • ToOrdinal() - Ordinal number formatting (1st, 2nd, 3rd...)
  • NumberToWords() - Convert numbers to English words

๐ŸŒ Encoding & Web Utilities

Web-safe string encoding and decoding

  • HTMLEncode(), HTMLDecode() - HTML entity encoding for safe web output
  • URLEncode(), URLDecode() - URL parameter encoding/decoding
  • HexEncode(), HexDecode() - Hexadecimal string conversion

๐Ÿ“Š Text Analysis

Statistical analysis and text insights

  • CountWords(), GetWords() - Word counting and extraction
  • FleschKincaidReadability() - Readability scoring for content assessment
  • GenerateNGrams() - N-gram generation for linguistic analysis

๐Ÿ› ๏ธ String Utilities

Essential string manipulation operations

  • Split(), Join() - String splitting and joining operations
  • ReplaceText(), ReplaceRegEx() - Text replacement with regex support
  • Contains(), StartsWith(), EndsWith() - String content inspection
  • CollapseWhitespace(), RemoveWhitespace() - Whitespace normalization
  • DuplicateText(), ReverseText() - String duplication and reversal
  • GetLength(), SubString(), LeftStr(), RightStr() - String length and extraction
  • CountSubString() - Substring occurrence counting

๐Ÿงถ Installation (Lazarus IDE)

Quick setup for Lazarus development

  1. Clone the repository:
git clone https://github.com/ikelaiah/stringkit-fp
  1. Open your project - Open/start a new project in Lazarus IDE

  2. Add the package - Go to Package โ†’ Open Package File (.lpk)...

  3. Select the package - Navigate to the StringKit packages in the packages/lazarus/ folder and select stringkit_fp.lpk

  4. Compile the package - In the package window that opens, click Compile

  5. Install to project - Click Use โ†’ Add to Project to install the package

โœ… Installation complete! StringKit is now available in your Lazarus project.

๐Ÿงต Manual Installation (General)

Alternative setup method

  1. Clone the repository:
git clone https://github.com/ikelaiah/stringkit-fp
  1. Configure your project - Add the source directory to your project's search path.

๐Ÿงต Usage

Import StringKit into your project

uses
  // String manipulation library
  StringKit;           // All string operations

๐Ÿš€ Quick Start

Minimal end-to-end usage with static and helper APIs:

uses
  SysUtils,
  StringKit,
  StringKitHelper; // enable instance-style helper

begin
  // Validation (helper)
  if 'user@example.com'.IsValidEmail then
    WriteLn('Valid email');

  // Formatting (static)
  WriteLn(TStringKit.FormatFileSize(1048576)); // 1.00 MB

  // Encoding (helper)
  WriteLn('foo'.Encode64); // Zm9v
end.

๐Ÿงฉ Instance-Style API via Type Helpers

StringKit also provides a string type helper for more natural, instance-style calls.

uses
  StringKit, StringKitHelper; // Enable helper-backed instance methods on 'string'

var
  S: string;
begin
  // Instance-style calls (via TStringHelperEx)
  S := '  hello world  '.Trim;                // 'hello world'
  S := 'Hello World'.ToSnakeCase;             // 'hello_world'
  if 'user@example.com'.IsValidEmail then ;   // True
  S := 'Hello World!'.URLEncode;              // 'Hello+World%21'
  S := 'foo'.Encode64;                        // 'Zm9v'

  // Equivalent static calls still work
  S := TStringKit.Trim('  hello world  ');
end;

Notes:

  • Add StringKitHelper to your unit's uses clause to enable helper methods.
  • Most TStringKit string-first methods are available via the helper for convenience; methods that don't operate on a source string may remain as static calls.

โš™๏ธ Modular Helper via Feature Flags (1.6.0+)

As of 1.6.0, TStringHelperEx is modularized using conditional includes to let you select which groups compile into the helper.

  • Default: if no symbols are defined, SK_ALL enables all groups.
  • Selective mode: define SK_ANY and then enable specific groups you need.

Available groups:

  • SK_MANIP โ€” trim, pad, collapse whitespace, reverse, length, substring
  • SK_MATCH โ€” regex match/extract, contains/starts/ends, words, counts
  • SK_COMPARE โ€” Levenshtein, Hamming, Jaro/Jaro-Winkler, LCS, fuzzy
  • SK_CASE โ€” title, camel, pascal, snake, kebab
  • SK_VALIDATE โ€” email, URL, IP (v4/v6), date
  • SK_FORMAT โ€” truncate, file size, number/float formatting
  • SK_NUMERIC โ€” roman, ordinal, number-to-words, from-roman
  • SK_ENCODE โ€” hex, base64, HTML, URL encode/decode
  • SK_SPLIT โ€” split, join
  • SK_PHONETIC โ€” soundex, metaphone, readability, ngrams, basic counts

Notes:

  • Implementation and interface includes live under src/inc/ and are pulled from src/StringKitHelper.pas using {$I ...}.
  • When SK_ALL (default) is active, the helper API matches the full surface as before.
  • See also: CHANGELOG 1.6.0 for the summary.
๐Ÿš€ SK_ENCODE Quick Start (helper-only)

Enable only encoding/decoding helpers via feature flags, then use StringKitHelper without static calls.

  • Lazarus (FPC): Project Options > Compiler Options > Custom Options
    • -dSK_ANY -dSK_ENCODE

Uses:

uses SysUtils, StringKitHelper;

Examples:

begin
  // 1) Base64
  WriteLn('foo'.Encode64);    // Zm9v
  WriteLn('Zm9v'.Decode64);   // foo

  // 2) URL
  WriteLn('Hello World!'.URLEncode);    // Hello+World%21
  WriteLn('Hello+World%21'.URLDecode);  // Hello World!

  // 3) HTML
  WriteLn('<b>Hi</b>'.HTMLEncode);           // &lt;b&gt;Hi&lt;/b&gt;
  WriteLn('&lt;b&gt;Hi&lt;/b&gt;'.HTMLDecode);  // <b>Hi</b>

  // 4) Hex
  WriteLn('abc'.HexEncode);     // 616263
  WriteLn('616263'.HexDecode);  // abc

  // 5) Chaining (HTML then URL)
  WriteLn('<p class="x">'.HTMLEncode.URLEncode);
end.

Note on defines scope:

  • {$DEFINE ...} inside your program controls conditional blocks in your program only. It does not affect how src/StringKitHelper.pas is compiled in a separate unit.
  • To actually compile the helper with only SK_ENCODE, set defines at the project/build level so the compiler sees them when compiling StringKitHelper.pas:
    • Lazarus/FPC: Project Options > Compiler Options > Custom Options โ†’ -dSK_ANY -dSK_ENCODE

๐ŸŽจ Start Weaving: Quick Thread Patterns

๐ŸŽจ Thread Dyeing & Styling

Transform your raw strings into beautifully styled threads

var
  Text: string;
begin
  // Case conversions
  Text := TStringKit.ToCamelCase('hello world');     // Returns: 'helloWorld'
  Text := TStringKit.ToPascalCase('hello world');    // Returns: 'HelloWorld'
  Text := TStringKit.ToSnakeCase('HelloWorld');      // Returns: 'hello_world'
  Text := TStringKit.ToKebabCase('HelloWorld');      // Returns: 'hello-world'
  Text := TStringKit.ToTitleCase('hello world');     // Returns: 'Hello World'
  
  // Padding and formatting
  Text := TStringKit.PadLeft('123', 8, '0');         // Returns: '00000123'
  Text := TStringKit.PadRight('Name', 10, '.');      // Returns: 'Name......'
  Text := TStringKit.PadCenter('Hi', 10, '-');       // Returns: '----Hi----'
  Text := TStringKit.Truncate('Very long text', 10); // Returns: 'Very lo...'
  Text := TStringKit.CapitalizeText('hello world');  // Returns: 'Hello World'
end;

๐Ÿ” Quality Control & Pattern Weaving

Inspect your threads and extract beautiful patterns

var
  Matches: TMatchesResults;
  AllMatches: TStringDynArray;
  i: Integer;
begin
  // Built-in validators
  if TStringKit.IsValidEmail('user@example.com') then
    WriteLn('Valid email');
  if TStringKit.IsValidURL('https://example.com') then
    WriteLn('Valid URL');
  if TStringKit.IsValidIPv4('192.168.1.1') then
    WriteLn('Valid IPv4');
  if TStringKit.IsValidDate('2023-12-25', 'yyyy-mm-dd') then
    WriteLn('Valid date');
    
  // Pattern matching and extraction
  if TStringKit.MatchesPattern('ABC123', '^[A-Z]{3}\d{3}$') then
    WriteLn('Matches pattern');
    
  // Extract all matches with position info
  Matches := TStringKit.ExtractMatches('Call 555-1234 or 555-5678', '\d{3}-\d{4}');
  for i := 0 to High(Matches) do
    WriteLn(Format('Found: %s at position %d', [Matches[i].Text, Matches[i].Position]));
    
  // Extract just the matched text
  AllMatches := TStringKit.ExtractAllMatches('Emails: a@b.com, c@d.net', '\w+@\w+\.\w+');
  for i := 0 to High(AllMatches) do
    WriteLn('Email: ' + AllMatches[i]);
end;

๐Ÿงฌ Thread Similarity Analysis

Compare and measure the likeness between different thread types

var
  Distance: Integer;
  Similarity: Double;
begin
  // String distance algorithms
  Distance := TStringKit.LevenshteinDistance('kitten', 'sitting'); // Returns: 3
  Distance := TStringKit.HammingDistance('karolin', 'kathrin');     // Returns: 3
  
  // Similarity ratios (0.0 to 1.0)
  Similarity := TStringKit.LevenshteinSimilarity('test', 'best');   // Returns: ~0.75
  Similarity := TStringKit.JaroSimilarity('MARTHA', 'MARHTA');      // Returns: ~0.94
  Similarity := TStringKit.JaroWinklerSimilarity('MARTHA', 'MARHTA'); // Higher than Jaro
  
  // Fuzzy matching with threshold
  if TStringKit.IsFuzzyMatch('apple', 'appel', 0.8) then
    WriteLn('Close match found');
    
  // Longest common subsequence
  WriteLn(TStringKit.LongestCommonSubsequence('ABCDEFG', 'ABDZEFXG')); // Returns: 'ABDEG'
end;

๐ŸŽต Sound Thread Identification

Match threads by their sonic fingerprint

var
  Code1, Code2: string;
begin
  // Soundex for name matching
  Code1 := TStringKit.Soundex('Robert');  // Returns: 'R163'
  Code2 := TStringKit.Soundex('Rupert');  // Returns: 'R163'
  if Code1 = Code2 then
    WriteLn('Names sound similar');
    
  // Metaphone for pronunciation
  Code1 := TStringKit.Metaphone('knight');   // Returns: 'NT'
  Code2 := TStringKit.Metaphone('night');    // Returns: 'NT'
  if Code1 = Code2 then
    WriteLn('Words sound the same');
end;

๐Ÿ›๏ธ Number Thread Artistry

Spin numbers into elegant, readable thread patterns

var
  Roman: string;
  Number: Integer;
  Formatted: string;
begin
  // Roman numerals
  Roman := TStringKit.ToRoman(1994);        // Returns: 'MCMXCIV'
  Number := TStringKit.FromRoman('MCMXCIV'); // Returns: 1994
  
  // File size formatting
  Formatted := TStringKit.FormatFileSize(1048576);    // Returns: '1.00 MB'
  Formatted := TStringKit.FormatFileSize(1500000000); // Returns: '1.40 GB'
  
  // Number formatting
  Formatted := TStringKit.FormatNumber(1234567);           // Returns: '1,234,567'
  Formatted := TStringKit.FormatFloat(12345.67, 2);       // Returns: '12,345.67'
  Formatted := TStringKit.FormatFloat(1234.5, 3, ',', '.'); // Returns: '1.234,500'
  
  // Ordinal and word conversion
  Formatted := TStringKit.ToOrdinal(21);              // Returns: '21st'
  Formatted := TStringKit.NumberToWords(123);         // Returns: 'one hundred and twenty-three'
end;

๐ŸŒ Web Thread Preparation

Ready your threads for the digital tapestry of the web

var
  Encoded, Decoded: string;
begin
  // HTML encoding for safe web content
  Encoded := TStringKit.HTMLEncode('<p class="bold">Text</p>');
  // Returns: '&lt;p class=&quot;bold&quot;&gt;Text&lt;/p&gt;'
  
  Decoded := TStringKit.HTMLDecode('&lt;p&gt;Hello &amp; World&lt;/p&gt;');
  // Returns: '<p>Hello & World</p>'
  
  // URL encoding for web parameters
  Encoded := TStringKit.URLEncode('Hello World!');     // Returns: 'Hello+World%21'
  Decoded := TStringKit.URLDecode('Hello+World%21');   // Returns: 'Hello World!'
  
  // Base64 encoding/decoding
  Encoded := TStringKit.Encode64('foo');               // Returns: 'Zm9v'
  Decoded := TStringKit.Decode64('Zm8=');              // Returns: 'fo'
  
  // Hexadecimal encoding
  Encoded := TStringKit.HexEncode('Hello');            // Returns: '48656C6C6F'
  Decoded := TStringKit.HexDecode('48656C6C6F');       // Returns: 'Hello'
end;

๐Ÿ“Š Thread Analysis & Insights

Examine your woven text like a master craftsperson

var
  WordCount: Integer;
  Readability: Double;
  NGrams: TStringDynArray;
  i: Integer;
begin
  // Basic text statistics
  WordCount := TStringKit.CountWords('Hello, world! How are you?'); // Returns: 5
  
  // Readability scoring (0-100, higher = easier)
  Readability := TStringKit.FleschKincaidReadability('The quick brown fox jumps.');
  WriteLn(Format('Readability score: %.1f', [Readability]));
  
  // N-gram generation for NLP
  NGrams := TStringKit.GenerateNGrams('the quick brown fox', 2); // Bigrams
  for i := 0 to High(NGrams) do
    WriteLn('Bigram: ' + NGrams[i]);
  // Output: 'the quick', 'quick brown', 'brown fox'
end;

๐Ÿ› ๏ธ Master Weaver's Essential Tools

The fundamental techniques every string artisan must know

var
  Parts: TStringDynArray;
  Joined: string;
  i: Integer;
begin
  // Splitting and joining
  Parts := TStringKit.Split('apple,banana,cherry', ',');
  for i := 0 to High(Parts) do
    WriteLn('Part: ' + Parts[i]);
    
  Joined := TStringKit.Join(Parts, ' | '); // Returns: 'apple | banana | cherry'
  
  // Text replacement
  Joined := TStringKit.ReplaceText('Hello World', 'World', 'Pascal');
  // Returns: 'Hello Pascal'
  
  Joined := TStringKit.ReplaceRegEx('Phone: 123-456-7890', '(\d{3})-(\d{3})-(\d{4})', '($1) $2-$3');
  // Returns: 'Phone: (123) 456-7890'
  
  // String testing
  if TStringKit.StartsWith('Hello World', 'Hello') then
    WriteLn('Starts with Hello');
  if TStringKit.EndsWith('test.txt', '.txt') then
    WriteLn('Is a text file');
  if TStringKit.Contains('Hello World', 'World') then
    WriteLn('Contains World');
    
  // Text cleaning
  Joined := TStringKit.CollapseWhitespace('  Multiple   spaces  '); // Returns: ' Multiple spaces '
  Joined := TStringKit.RemoveWhitespace('  No spaces  ');          // Returns: 'Nospaces'
  
  // String extraction and manipulation
  Joined := TStringKit.LeftStr('Hello World', 5);     // Returns: 'Hello'
  Joined := TStringKit.RightStr('Hello World', 5);    // Returns: 'World'
  Joined := TStringKit.SubString('Hello World', 7, 5); // Returns: 'World'
  Joined := TStringKit.DuplicateText('Hi! ', 3);      // Returns: 'Hi! Hi! Hi! '
  
  // String analysis
  WriteLn(TStringKit.GetLength('Hello'));             // Returns: 5
  WriteLn(TStringKit.CountSubString('ababab', 'ab')); // Returns: 3
end;

๐Ÿ“– System Requirements

Tested Environments

Module Windows 11 Ubuntu 24.04.2
StringKit โœ… โœ…

Dependencies

  • Windows
    • No external dependencies required
  • Linux
    • No external dependencies required
  • Uses only standard Free Pascal RTL units

Build Requirements

  • Free Pascal Compiler (FPC) 3.2.2+
  • Lazarus 4.0+
  • Basic development tools (git, terminal, etc)

๐Ÿ“š Documentation

For detailed documentation, see:

โœ… Testing

  1. Open the TestRunner.lpi using Lazarus IDE
  2. Compile the project
  3. Run the Test Runner:
$ cd tests
$ ./TestRunner.exe -a --format=plain

๐Ÿงญ Future Weaving Patterns

Our roadmap for expanding the string artisan's toolkit

  • Remove custom types and use RTL types
  • Introduce custom method for hashing
  • Enhance multi-byte character weaving for global text tapestries
  • Seamless support for Free Pascal and Lazarus package managers

๐Ÿค Join the Weaving Circle

Every master weaver started as an apprentice - your contributions help strengthen our tapestry!

Contributions are warmly welcomed! Whether you're adding new thread patterns, fixing loose ends, or improving our weaving techniques, please feel free to submit a Pull Request. For major pattern changes, please open an issue first to discuss your vision.

  1. Fork the Loom - Fork the Project
  2. Create your Pattern - Create your Feature Branch (git checkout -b feature/AmazingThreadPattern)
  3. Weave your Changes - Commit your Changes (git commit -m 'Add beautiful new thread pattern')
  4. Share your Work - Push to the Branch (git push origin feature/AmazingThreadPattern)
  5. Present to the Guild - Open a Pull Request

โš–๏ธ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Honoring Our Thread Masters

Standing on the shoulders of giants who wove the foundation

  • ๐Ÿ›๏ธ The FPC Guild - For crafting the magnificent Free Pascal loom
  • ๐Ÿงต Fellow Weavers - All contributors and maintainers who help strengthen our tapestry
  • ๐ŸŽจ String Artisans Everywhere - The community that inspires continuous innovation

๐Ÿงถ Ready to start weaving? Your feedback helps us craft better tools! Visit our thread workshop to share ideas, report loose threads, or track our weaving progress.


โœจ Happy String Weaving! โœจ

"In every thread lies infinite possibility, in every string a story waiting to be told."