Ecng.StringSearch 1.0.268

dotnet add package Ecng.StringSearch --version 1.0.268
                    
NuGet\Install-Package Ecng.StringSearch -Version 1.0.268
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.

                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.

                    
Directory.Packages.props

                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ecng.StringSearch --version 1.0.268
                    
#r "nuget: Ecng.StringSearch, 1.0.268"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ecng.StringSearch@1.0.268
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ecng.StringSearch&version=1.0.268
                    
Install as a Cake Addin
#tool nuget:?package=Ecng.StringSearch&version=1.0.268
                    
Install as a Cake Tool

StringSearch - Efficient String Search Data Structures

A collection of high-performance string search data structures including Trie, Patricia Trie, and Ukkonen's Suffix Tree implementations. These data structures are optimized for fast prefix and substring searching operations.

Features

  • Multiple trie implementations for different use cases
  • Fast prefix and substring searching
  • Generic value associations with string keys
  • Memory-efficient Patricia Trie (compressed trie)
  • Ukkonen's Suffix Tree for advanced substring searching
  • Concurrent trie support for multi-threaded scenarios
  • MIT licensed open-source implementation

Installation

Add a reference to the StringSearch project in your solution.

Quick Start

Basic Trie Usage

using Gma.DataStructures.StringSearch;

// Create a Patricia Trie (most commonly used)
var trie = new PatriciaTrie();

// Add key-value pairs
trie.Add("apple", 1);
trie.Add("application", 2);
trie.Add("apply", 3);
trie.Add("banana", 4);

// Retrieve values by prefix
var results = trie.Retrieve("app");
// Returns: [1, 2, 3] (values associated with "apple", "application", "apply")

var results2 = trie.Retrieve("ban");
// Returns: [4] (value associated with "banana")

Data Structures

PatriciaTrie

A space-optimized trie (radix tree) that stores strings efficiently by compressing chains of nodes with single children.

Best for:

  • Prefix searching
  • Autocomplete features
  • Memory-efficient storage of strings with common prefixes
using Gma.DataStructures.StringSearch;

var trie = new PatriciaTrie();

// Add entries
trie.Add("test", "Test Value");
trie.Add("testing", "Testing Value");
trie.Add("tester", "Tester Value");
trie.Add("tea", "Tea Value");

// Search by prefix
var results = trie.Retrieve("test");
// Returns: ["Test Value", "Testing Value", "Tester Value"]

var results2 = trie.Retrieve("te");
// Returns: ["Test Value", "Testing Value", "Tester Value", "Tea Value"]

PatriciaSuffixTrie

A Patricia Trie that indexes all suffixes of added strings, enabling substring searching.

Best for:

  • Substring searching
  • Finding all occurrences of a pattern within stored strings
  • "Contains" queries
using Gma.DataStructures.StringSearch;

// Create with minimum query length of 3 characters
var suffixTrie = new PatriciaSuffixTrie(minQueryLength: 3);

// Add strings with associated values
suffixTrie.Add("hello world", "Document 1");
suffixTrie.Add("world peace", "Document 2");
suffixTrie.Add("hello there", "Document 3");

// Search for substring "wor"
var results = suffixTrie.Retrieve("wor");
// Returns: ["Document 1", "Document 2"] (both contain "world")

// Search for substring "hello"
var results2 = suffixTrie.Retrieve("hello");
// Returns: ["Document 1", "Document 3"]

SuffixTrie

A standard trie-based suffix tree implementation.

using Gma.DataStructures.StringSearch;

// Create with minimum suffix length of 2
var suffixTrie = new SuffixTrie(minSuffixLength: 2);

suffixTrie.Add("programming", "Item 1");
suffixTrie.Add("grammar", "Item 2");

// Search for "gram"
var results = suffixTrie.Retrieve("gram");
// Returns: ["Item 1", "Item 2"] (both contain "gram")

UkkonenTrie

An implementation of Ukkonen's linear-time suffix tree construction algorithm.

Best for:

  • Large text indexing
  • Efficient substring search in big datasets
  • Advanced pattern matching
using Gma.DataStructures.StringSearch;

// Create with minimum suffix length
var ukkonen = new UkkonenTrie(minSuffixLength: 3);

ukkonen.Add("banana", "Fruit 1");
ukkonen.Add("bandana", "Clothing 1");

// Search for "ana"
var results = ukkonen.Retrieve("ana");
// Returns: ["Fruit 1", "Clothing 1"]

ConcurrentTrie

Thread-safe trie implementation for concurrent access scenarios.

using Gma.DataStructures.StringSearch;
using System.Threading.Tasks;

var concurrentTrie = new ConcurrentTrie();

// Safe for concurrent access
Parallel.For(0, 1000, i =>
{
    concurrentTrie.Add($"key{i}", i);
});

// Retrieve from multiple threads
var results = concurrentTrie.Retrieve("key1");

Common Interface: ITrie

All trie implementations implement the ITrie interface:

public interface ITrie
{
    void Add(string key, TValue value);
    IEnumerable Retrieve(string query);
    void Remove(TValue value);
    void RemoveRange(IEnumerable values);
    void Clear();
}

Usage Examples

Autocomplete System

using Gma.DataStructures.StringSearch;

public class AutocompleteSystem
{
    private readonly PatriciaTrie _trie;

    public AutocompleteSystem()
    {
        _trie = new PatriciaTrie();
    }

    public void AddWord(string word)
    {
        _trie.Add(word.ToLower(), word);
    }

    public IEnumerable GetSuggestions(string prefix)
    {
        return _trie.Retrieve(prefix.ToLower()).Distinct();
    }
}

// Usage
var autocomplete = new AutocompleteSystem();
autocomplete.AddWord("Apple");
autocomplete.AddWord("Application");
autocomplete.AddWord("Approach");
autocomplete.AddWord("Banana");

var suggestions = autocomplete.GetSuggestions("app");
// Returns: ["Apple", "Application", "Approach"]

Document Search Engine

using Gma.DataStructures.StringSearch;
using System.Linq;

public class DocumentSearchEngine
{
    private readonly PatriciaSuffixTrie _index;

    public DocumentSearchEngine(int minQueryLength = 3)
    {
        _index = new PatriciaSuffixTrie(minQueryLength);
    }

    public void IndexDocument(string documentId, string content)
    {
        // Index the document content
        _index.Add(content.ToLower(), documentId);
    }

    public IEnumerable Search(string query)
    {
        if (query.Length < 3)
            return Enumerable.Empty();

        return _index.Retrieve(query.ToLower()).Distinct();
    }
}

// Usage
var searchEngine = new DocumentSearchEngine();
searchEngine.IndexDocument("doc1", "The quick brown fox jumps over the lazy dog");
searchEngine.IndexDocument("doc2", "A quick movement in the forest");
searchEngine.IndexDocument("doc3", "The lazy cat sleeps");

var results = searchEngine.Search("quick");
// Returns: ["doc1", "doc2"]

var results2 = searchEngine.Search("lazy");
// Returns: ["doc1", "doc3"]

Phone Directory

using Gma.DataStructures.StringSearch;

public class Contact
{
    public string Name { get; set; }
    public string Phone { get; set; }

    public override string ToString() => $"{Name}: {Phone}";
}

public class PhoneDirectory
{
    private readonly PatriciaTrie _trie;

    public PhoneDirectory()
    {
        _trie = new PatriciaTrie();
    }

    public void AddContact(string name, string phone)
    {
        var contact = new Contact { Name = name, Phone = phone };
        _trie.Add(name.ToLower(), contact);
    }

    public IEnumerable FindByPrefix(string namePrefix)
    {
        return _trie.Retrieve(namePrefix.ToLower());
    }

    public void RemoveContact(Contact contact)
    {
        _trie.Remove(contact);
    }

    public void Clear()
    {
        _trie.Clear();
    }
}

// Usage
var directory = new PhoneDirectory();
directory.AddContact("Alice Smith", "555-0001");
directory.AddContact("Alice Johnson", "555-0002");
directory.AddContact("Bob Brown", "555-0003");

var contacts = directory.FindByPrefix("alic");
// Returns all contacts starting with "alic"

IP Address Lookup

using Gma.DataStructures.StringSearch;

public class IpAddressLookup
{
    private readonly PatriciaTrie _trie;

    public IpAddressLookup()
    {
        _trie = new PatriciaTrie();
    }

    public void AddMapping(string ipPrefix, string location)
    {
        _trie.Add(ipPrefix, location);
    }

    public IEnumerable FindLocations(string ipPrefix)
    {
        return _trie.Retrieve(ipPrefix);
    }
}

// Usage
var ipLookup = new IpAddressLookup();
ipLookup.AddMapping("192.168.1", "Local Network A");
ipLookup.AddMapping("192.168.2", "Local Network B");
ipLookup.AddMapping("10.0.0", "VPN Network");

var locations = ipLookup.FindLocations("192.168");
// Returns: ["Local Network A", "Local Network B"]

Tag Search System

using Gma.DataStructures.StringSearch;
using System.Collections.Generic;

public class TaggedItem
{
    public string Id { get; set; }
    public string Title { get; set; }
    public List Tags { get; set; }
}

public class TagSearchSystem
{
    private readonly PatriciaTrie _tagIndex;

    public TagSearchSystem()
    {
        _tagIndex = new PatriciaTrie();
    }

    public void AddItem(TaggedItem item)
    {
        foreach (var tag in item.Tags)
        {
            _tagIndex.Add(tag.ToLower(), item);
        }
    }

    public IEnumerable SearchByTag(string tagPrefix)
    {
        return _tagIndex.Retrieve(tagPrefix.ToLower()).Distinct();
    }

    public void RemoveItem(TaggedItem item)
    {
        _tagIndex.Remove(item);
    }
}

// Usage
var tagSystem = new TagSearchSystem();

tagSystem.AddItem(new TaggedItem
{
    Id = "1",
    Title = "Article about C#",
    Tags = new List { "csharp", "programming", "dotnet" }
});

tagSystem.AddItem(new TaggedItem
{
    Id = "2",
    Title = "Article about C++",
    Tags = new List { "cpp", "programming", "native" }
});

var items = tagSystem.SearchByTag("prog");
// Returns both articles (both have "programming" tag)

var csharpItems = tagSystem.SearchByTag("csh");
// Returns only the first article
using Gma.DataStructures.StringSearch;

public class Symbol
{
    public string Name { get; set; }
    public string Type { get; set; }  // class, method, property, etc.
    public string FilePath { get; set; }
}

public class CodeSymbolIndex
{
    private readonly PatriciaTrie _symbolTrie;
    private readonly PatriciaSuffixTrie _substringTrie;

    public CodeSymbolIndex()
    {
        _symbolTrie = new PatriciaTrie();
        _substringTrie = new PatriciaSuffixTrie(minQueryLength: 2);
    }

    public void IndexSymbol(Symbol symbol)
    {
        var key = symbol.Name.ToLower();
        _symbolTrie.Add(key, symbol);
        _substringTrie.Add(key, symbol);
    }

    public IEnumerable SearchByPrefix(string prefix)
    {
        return _symbolTrie.Retrieve(prefix.ToLower());
    }

    public IEnumerable SearchBySubstring(string substring)
    {
        return _substringTrie.Retrieve(substring.ToLower());
    }
}

// Usage
var codeIndex = new CodeSymbolIndex();

codeIndex.IndexSymbol(new Symbol
{
    Name = "GetUserById",
    Type = "method",
    FilePath = "UserService.cs"
});

codeIndex.IndexSymbol(new Symbol
{
    Name = "UserRepository",
    Type = "class",
    FilePath = "UserRepository.cs"
});

// Prefix search
var prefixResults = codeIndex.SearchByPrefix("getuser");
// Returns: GetUserById

// Substring search
var substringResults = codeIndex.SearchBySubstring("user");
// Returns: GetUserById, UserRepository

Performance Characteristics

Data Structure Add Search Space Best Use Case
PatriciaTrie O(k) O(k) Low Prefix search, autocomplete
PatriciaSuffixTrie O(k²) O(k) Medium Substring search
SuffixTrie O(k²) O(k) High Suffix-based search
UkkonenTrie O(k) O(k) Medium Large text indexing
ConcurrentTrie O(k) O(k) Medium Multi-threaded scenarios

where k is the length of the string

Choosing the Right Data Structure

Use PatriciaTrie when:

  • You need prefix-based searching (autocomplete, type-ahead)
  • Memory efficiency is important
  • Your strings share common prefixes
  • You only need to find strings that START with a query

Use PatriciaSuffixTrie when:

  • You need substring searching (find strings CONTAINING a query)
  • You want to find all occurrences of a pattern
  • Memory usage is acceptable
  • Query strings have a minimum length

Use UkkonenTrie when:

  • You're indexing large amounts of text
  • You need the most efficient suffix tree construction
  • Substring search performance is critical
  • You have complex pattern matching requirements

Use ConcurrentTrie when:

  • Multiple threads need to access the trie simultaneously
  • Thread safety is required
  • You're building a shared index in a multi-threaded application

Important Notes

  1. Case Sensitivity: Most examples use .ToLower() for case-insensitive search. The trie itself is case-sensitive.

  2. Minimum Query Length: Suffix tries accept a minimum query/suffix length to reduce memory usage and improve performance.

  3. Duplicate Values: Retrieve() may return duplicate values if the same value was added with different keys. Use .Distinct() if needed.

  4. Remove Operations: Remove() removes all occurrences of a value, regardless of which keys it was added with.

  5. Thread Safety: Only ConcurrentTrie is thread-safe. Other implementations require external synchronization for concurrent access.

Target Frameworks

  • .NET Standard 2.0
  • .NET 6.0
  • .NET 10.0

License

This code is distributed under MIT license. Copyright (c) 2013 George Mamaladze See license.txt or http://opensource.org/licenses/mit-license.php

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Ecng.StringSearch:

Package Downloads
StockSharp.Algo

Trading algorithms. More info on web site https://stocksharp.com/store/

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on Ecng.StringSearch:

Repository Stars
StockSharp/StockSharp
Algorithmic trading and quantitative trading open source platform to develop trading robots (stock markets, forex, crypto, bitcoins, and options).
Version Downloads Last Updated
1.0.268 320 9/25/2026
1.0.267 753 9/13/2026
1.0.266 145 9/10/2026
1.0.265 754 8/30/2026
1.0.264 629 8/26/2026
1.0.263 1,092 8/20/2026
1.0.262 866 8/13/2026
1.0.261 136 8/12/2026
1.0.260 615 8/4/2026
1.0.259 185 8/3/2026
1.0.258 245 8/2/2026
1.0.257 145 8/2/2026
1.0.256 241 8/1/2026
1.0.255 2,262 7/8/2026
1.0.254 457 6/20/2026
1.0.253 384 6/17/2026
1.0.252 281 6/12/2026
1.0.251 515 5/15/2026
1.0.250 146 5/14/2026
1.0.249 292 5/3/2026
Loading failed