![]() |
VOOZH | about |
dotnet add package Ecng.StringSearch --version 1.0.253
NuGet\Install-Package Ecng.StringSearch -Version 1.0.253
<PackageReference Include="Ecng.StringSearch" Version="1.0.253" />
<PackageVersion Include="Ecng.StringSearch" Version="1.0.253" />Directory.Packages.props
<PackageReference Include="Ecng.StringSearch" />Project file
paket add Ecng.StringSearch --version 1.0.253
#r "nuget: Ecng.StringSearch, 1.0.253"
#:package Ecng.StringSearch@1.0.253
#addin nuget:?package=Ecng.StringSearch&version=1.0.253Install as a Cake Addin
#tool nuget:?package=Ecng.StringSearch&version=1.0.253Install as a Cake Tool
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.
Add a reference to the StringSearch project in your solution.
using Gma.DataStructures.StringSearch;
// Create a Patricia Trie (most commonly used)
var trie = new PatriciaTrie<int>();
// 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")
A space-optimized trie (radix tree) that stores strings efficiently by compressing chains of nodes with single children.
Best for:
using Gma.DataStructures.StringSearch;
var trie = new PatriciaTrie<string>();
// 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"]
A Patricia Trie that indexes all suffixes of added strings, enabling substring searching.
Best for:
using Gma.DataStructures.StringSearch;
// Create with minimum query length of 3 characters
var suffixTrie = new PatriciaSuffixTrie<string>(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"]
A standard trie-based suffix tree implementation.
using Gma.DataStructures.StringSearch;
// Create with minimum suffix length of 2
var suffixTrie = new SuffixTrie<string>(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")
An implementation of Ukkonen's linear-time suffix tree construction algorithm.
Best for:
using Gma.DataStructures.StringSearch;
// Create with minimum suffix length
var ukkonen = new UkkonenTrie<string>(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"]
Thread-safe trie implementation for concurrent access scenarios.
using Gma.DataStructures.StringSearch;
using System.Threading.Tasks;
var concurrentTrie = new ConcurrentTrie<int>();
// Safe for concurrent access
Parallel.For(0, 1000, i =>
{
concurrentTrie.Add($"key{i}", i);
});
// Retrieve from multiple threads
var results = concurrentTrie.Retrieve("key1");
All trie implementations implement the ITrie<TValue> interface:
public interface ITrie<TValue>
{
void Add(string key, TValue value);
IEnumerable<TValue> Retrieve(string query);
void Remove(TValue value);
void RemoveRange(IEnumerable<TValue> values);
void Clear();
}
using Gma.DataStructures.StringSearch;
public class AutocompleteSystem
{
private readonly PatriciaTrie<string> _trie;
public AutocompleteSystem()
{
_trie = new PatriciaTrie<string>();
}
public void AddWord(string word)
{
_trie.Add(word.ToLower(), word);
}
public IEnumerable<string> 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"]
using Gma.DataStructures.StringSearch;
using System.Linq;
public class DocumentSearchEngine
{
private readonly PatriciaSuffixTrie<string> _index;
public DocumentSearchEngine(int minQueryLength = 3)
{
_index = new PatriciaSuffixTrie<string>(minQueryLength);
}
public void IndexDocument(string documentId, string content)
{
// Index the document content
_index.Add(content.ToLower(), documentId);
}
public IEnumerable<string> Search(string query)
{
if (query.Length < 3)
return Enumerable.Empty<string>();
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"]
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<Contact> _trie;
public PhoneDirectory()
{
_trie = new PatriciaTrie<Contact>();
}
public void AddContact(string name, string phone)
{
var contact = new Contact { Name = name, Phone = phone };
_trie.Add(name.ToLower(), contact);
}
public IEnumerable<Contact> 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"
using Gma.DataStructures.StringSearch;
public class IpAddressLookup
{
private readonly PatriciaTrie<string> _trie;
public IpAddressLookup()
{
_trie = new PatriciaTrie<string>();
}
public void AddMapping(string ipPrefix, string location)
{
_trie.Add(ipPrefix, location);
}
public IEnumerable<string> 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"]
using Gma.DataStructures.StringSearch;
using System.Collections.Generic;
public class TaggedItem
{
public string Id { get; set; }
public string Title { get; set; }
public List<string> Tags { get; set; }
}
public class TagSearchSystem
{
private readonly PatriciaTrie<TaggedItem> _tagIndex;
public TagSearchSystem()
{
_tagIndex = new PatriciaTrie<TaggedItem>();
}
public void AddItem(TaggedItem item)
{
foreach (var tag in item.Tags)
{
_tagIndex.Add(tag.ToLower(), item);
}
}
public IEnumerable<TaggedItem> 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<string> { "csharp", "programming", "dotnet" }
});
tagSystem.AddItem(new TaggedItem
{
Id = "2",
Title = "Article about C++",
Tags = new List<string> { "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<Symbol> _symbolTrie;
private readonly PatriciaSuffixTrie<Symbol> _substringTrie;
public CodeSymbolIndex()
{
_symbolTrie = new PatriciaTrie<Symbol>();
_substringTrie = new PatriciaSuffixTrie<Symbol>(minQueryLength: 2);
}
public void IndexSymbol(Symbol symbol)
{
var key = symbol.Name.ToLower();
_symbolTrie.Add(key, symbol);
_substringTrie.Add(key, symbol);
}
public IEnumerable<Symbol> SearchByPrefix(string prefix)
{
return _symbolTrie.Retrieve(prefix.ToLower());
}
public IEnumerable<Symbol> 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
| 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
Case Sensitivity: Most examples use .ToLower() for case-insensitive search. The trie itself is case-sensitive.
Minimum Query Length: Suffix tries accept a minimum query/suffix length to reduce memory usage and improve performance.
Duplicate Values: Retrieve() may return duplicate values if the same value was added with different keys. Use .Distinct() if needed.
Remove Operations: Remove() removes all occurrences of a value, regardless of which keys it was added with.
Thread Safety: Only ConcurrentTrie is thread-safe. Other implementations require external synchronization for concurrent access.
This code is distributed under MIT license. Copyright (c) 2013 George Mamaladze See license.txt or http://opensource.org/licenses/mit-license.php
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
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/ |
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.253 | 95 | 6/17/2026 |
| 1.0.252 | 209 | 6/12/2026 |
| 1.0.251 | 479 | 5/15/2026 |
| 1.0.250 | 104 | 5/14/2026 |
| 1.0.249 | 255 | 5/3/2026 |
| 1.0.248 | 491 | 4/14/2026 |
| 1.0.247 | 1,066 | 3/17/2026 |
| 1.0.246 | 141 | 3/17/2026 |
| 1.0.245 | 181 | 3/15/2026 |
| 1.0.244 | 534 | 3/3/2026 |
| 1.0.243 | 241 | 2/28/2026 |
| 1.0.242 | 858 | 2/4/2026 |
| 1.0.241 | 300 | 2/1/2026 |
| 1.0.240 | 200 | 1/26/2026 |
| 1.0.239 | 155 | 1/22/2026 |
| 1.0.238 | 219 | 1/19/2026 |
| 1.0.237 | 126 | 1/19/2026 |
| 1.0.236 | 125 | 1/18/2026 |
| 1.0.235 | 124 | 1/18/2026 |
| 1.0.234 | 195 | 1/14/2026 |
StringSearch: allocate ConcurrentTrieNode children only on a real miss