- Why Choose StringKit-FP?
- Feature Overview
- Installation (Lazarus IDE)
- Manual Installation (General)
- Usage
- Start Weaving: Quick Thread Patterns
- System Requirements
- Documentation
- Testing
- License
- Changelog
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
Professional text styling and formatting
ToUpper(),ToLower(),ToTitleCase()- Standard case transformationsToCamelCase(),ToPascalCase(),ToSnakeCase(),ToKebabCase()- Modern naming conventionsPadLeft(),PadRight(),PadCenter()- Text alignment with custom paddingTruncate()- Smart text truncation with ellipsis supportCapitalizeText()- Intelligent word capitalization
Robust string validation and pattern extraction
IsValidEmail(),IsValidURL(),IsValidIP()- Comprehensive format validationIsValidDate()- Date validation with custom format supportMatchesPattern()- Powerful regex pattern matchingExtractMatches(),ExtractAllMatches()- Extract matching substrings
Advanced string comparison algorithms
LevenshteinDistance(),LevenshteinSimilarity()- Edit distance calculationsHammingDistance()- Character-by-character comparison for equal-length stringsJaroSimilarity(),JaroWinklerSimilarity()- Sophisticated similarity metricsLongestCommonSubsequence(),LCSSimilarity()- Common subsequence analysisIsFuzzyMatch()- Multi-algorithm fuzzy string matching
Sound-based string comparison algorithms
Soundex()- Russell-Odell phonetic algorithm for name matchingMetaphone()- Advanced English pronunciation-based matching
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 formattingToOrdinal()- Ordinal number formatting (1st, 2nd, 3rd...)NumberToWords()- Convert numbers to English words
Web-safe string encoding and decoding
HTMLEncode(),HTMLDecode()- HTML entity encoding for safe web outputURLEncode(),URLDecode()- URL parameter encoding/decodingHexEncode(),HexDecode()- Hexadecimal string conversion
Statistical analysis and text insights
CountWords(),GetWords()- Word counting and extractionFleschKincaidReadability()- Readability scoring for content assessmentGenerateNGrams()- N-gram generation for linguistic analysis
Essential string manipulation operations
Split(),Join()- String splitting and joining operationsReplaceText(),ReplaceRegEx()- Text replacement with regex supportContains(),StartsWith(),EndsWith()- String content inspectionCollapseWhitespace(),RemoveWhitespace()- Whitespace normalizationDuplicateText(),ReverseText()- String duplication and reversalGetLength(),SubString(),LeftStr(),RightStr()- String length and extractionCountSubString()- Substring occurrence counting
Quick setup for Lazarus development
- Clone the repository:
git clone https://github.com/ikelaiah/stringkit-fp-
Open your project - Open/start a new project in Lazarus IDE
-
Add the package - Go to
Package→Open Package File (.lpk)... -
Select the package - Navigate to the StringKit packages in the
packages/lazarus/folder and selectstringkit_fp.lpk -
Compile the package - In the package window that opens, click
Compile -
Install to project - Click
Use → Add to Projectto install the package
✅ Installation complete! StringKit is now available in your Lazarus project.
Alternative setup method
- Clone the repository:
git clone https://github.com/ikelaiah/stringkit-fp- Configure your project - Add the source directory to your project's search path.
Import StringKit into your project
uses
// String manipulation library
StringKit; // All string operationsMinimal 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.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
StringKitHelperto your unit'susesclause to enable helper methods. - Most
TStringKitstring-first methods are available via the helper for convenience; methods that don't operate on a source string may remain as static calls.
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_ALLenables all groups. - Selective mode: define
SK_ANYand then enable specific groups you need.
Available groups:
SK_MANIP— trim, pad, collapse whitespace, reverse, length, substringSK_MATCH— regex match/extract, contains/starts/ends, words, countsSK_COMPARE— Levenshtein, Hamming, Jaro/Jaro-Winkler, LCS, fuzzySK_CASE— title, camel, pascal, snake, kebabSK_VALIDATE— email, URL, IP (v4/v6), dateSK_FORMAT— truncate, file size, number/float formattingSK_NUMERIC— roman, ordinal, number-to-words, from-romanSK_ENCODE— hex, base64, HTML, URL encode/decodeSK_SPLIT— split, joinSK_PHONETIC— soundex, metaphone, readability, ngrams, basic counts
Notes:
- Implementation and interface includes live under
src/inc/and are pulled fromsrc/StringKitHelper.pasusing{$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.
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); // <b>Hi</b>
WriteLn('<b>Hi</b>'.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 howsrc/StringKitHelper.pasis 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 compilingStringKitHelper.pas:- Lazarus/FPC: Project Options > Compiler Options > Custom Options →
-dSK_ANY -dSK_ENCODE
- Lazarus/FPC: Project Options > Compiler Options > Custom Options →
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;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;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;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;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;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: '<p class="bold">Text</p>'
Decoded := TStringKit.HTMLDecode('<p>Hello & World</p>');
// 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;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;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;The examples/ folder contains ready-to-run programs demonstrating StringKit-FP features:
A comprehensive demonstration program showing all major StringKit-FP functionality:
fpc -Fu./src ./examples/StringKitExample/StringKitExample.pas
./StringKitExampleThis example covers:
- Basic string operations (trim, case conversion, padding)
- Pattern matching and validation
- String similarity algorithms
- Text analysis and formatting
- Web encoding (HTML, URL, Base64)
- Number formatting and conversion
For selective feature compilation using feature flags:
CaseAndEncodeDemo - Compile with only CASE and ENCODE features:
fpc -dSK_ANY -dSK_CASE -dSK_ENCODE -Fu./src ./examples/directives/CaseAndEncodeDemo.pas
./CaseAndEncodeDemoEncodeOnlyDemo - Compile with only ENCODE feature:
fpc -dSK_ANY -dSK_ENCODE -Fu./src ./examples/directives/EncodeOnlyDemo.pas
./EncodeOnlyDemoThese examples demonstrate the modular helper system and how to build lightweight custom versions of StringKit-FP.
Q: Why does .Trim not work on my string?
A: Make sure you have StringKitHelper in your uses clause. Without it, you must use TStringKit.Trim() instead.
uses StringKit, StringKitHelper; // Add StringKitHelper to enable instance methods
S := ' hello '.Trim; // Now this works!Q: Can I use just the static methods without the helper?
A: Absolutely! The helper is optional. Use TStringKit.FunctionName() for static method calls without importing StringKitHelper.
uses StringKit; // Helper not needed for static methods
S := TStringKit.Trim(' hello '); // This always worksQ: What's the difference between the two approaches?
| Approach | Style | Requires StringKitHelper | Example |
|---|---|---|---|
| Instance-style | Modern, fluent | ✅ Yes | 'hello'.Trim |
| Static method | Traditional | ❌ No | TStringKit.Trim('hello') |
Both are equally valid - choose whichever you prefer!
| Module | Windows 11 | Ubuntu 24.04.2 |
|---|---|---|
| StringKit | ✅ | ✅ |
- Windows
- No external dependencies required
- Linux
- No external dependencies required
- Uses only standard Free Pascal RTL units
- Free Pascal Compiler (FPC) 3.2.2+
- Lazarus 4.0+
- Basic development tools (git, terminal, etc)
For detailed documentation, see:
- Open the
TestRunner.lpiusing Lazarus IDE - Compile the project
- Run the Test Runner:
$ cd tests
$ ./TestRunner.exe -a --format=plainOur 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
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.
- Fork the Loom - Fork the Project
- Create your Pattern - Create your Feature Branch (
git checkout -b feature/AmazingThreadPattern) - Weave your Changes - Commit your Changes (
git commit -m 'Add beautiful new thread pattern') - Share your Work - Push to the Branch (
git push origin feature/AmazingThreadPattern) - Present to the Guild - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
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."
