ZaString is a high-performance, zero-allocation string manipulation library for C# that uses Span and ReadOnlySpan for optimal memory efficiency. Built for .NET 8.0+, it provides a fluent API for building strings without heap allocations.
$ dotnet add package ZaStringZaString is a high-performance, zero-allocation string manipulation library for C# that uses Span<T> and
ReadOnlySpan<T> for optimal memory efficiency. Built for .NET 9.0+, it provides a fluent API for building strings
without heap allocations.
StringBuilderISpanFormattable types with formattingdotnet add package ZaString
using ZaString.Core;
using ZaString.Extensions;
// Create a stack-allocated buffer
Span<char> buffer = stackalloc char[100];
var builder = ZaSpanStringBuilder.Create(buffer);
// Build strings with fluent API
builder.Append("Hello, ")
.Append("World!")
.Append(" Number: ")
.Append(42)
.Append(" Pi: ")
.Append(Math.PI, "F2");
// Access result as span (zero allocation)
var result = builder.AsSpan();
Console.WriteLine(result); // "Hello, World! Number: 42 Pi: 3.14"The main string builder that writes directly to a provided Span<char>:
Span<char> buffer = stackalloc char[64];
var builder = ZaSpanStringBuilder.Create(buffer);
builder.Append("User: ")
.Append("John Doe")
.Append(", Age: ")
.Append(25)
.Append(", Active: ")
.Append(true);
// Access as ReadOnlySpan<char> (zero allocation)
var userInfo = builder.AsSpan();For scenarios requiring heap allocation with automatic buffer management:
using var builder = ZaPooledStringBuilder.Rent(128);
builder.Append("Pooled string building")
.Append(" with automatic cleanup");
var result = builder.ToString();
// Buffer automatically returned to pool when disposedUTF-8 byte-level string writing:
Span<byte> buffer = stackalloc byte[256];
var writer = ZaUtf8SpanWriter.Create(buffer);
writer.Append("Hello, UTF-8 World!")
.Append(" Number: ")
.Append(123);
var utf8Bytes = writer.AsSpan();var name = "Alice";
var age = 30;
var pi = Math.PI;
builder.Append($"User: {name}, Age: {age}, Pi: {pi:F2}");builder.Append("Currency: ")
.Append(1234.56, "C") // "$1,234.56"
.Append(", Number: ")
.Append(12345, "N0") // "12,345"
.Append(", Percentage: ")
.Append(0.85, "P2"); // "85.00%"var fr = new CultureInfo("fr-FR");
builder.Append(1234.56, "C", fr); // "1 234,56 €"var isActive = true;
builder.Append("Status: ")
.AppendIf(isActive, "Active", "Inactive");// JSON escaping
builder.AppendJsonEscaped("Line1\nLine2\t\"Quote\"");
// HTML escaping
builder.AppendHtmlEscaped("<script>alert('xss')</script>");
// URL encoding
builder.AppendUrlEncoded("Hello World!");
// CSV escaping
builder.AppendCsvEscaped("Value,with,commas");builder.AppendPathSegment("api")
.AppendPathSegment("v1")
.AppendPathSegment("users")
.AppendQueryParam("q", "search term", isFirst: true)
.AppendQueryParam("page", "1");
// Result: "api/v1/users?q=search%20term&page=1"Non-throwing variants for buffer overflow handling:
Span<char> smallBuffer = stackalloc char[10];
var builder = ZaSpanStringBuilder.Create(smallBuffer);
if (builder.TryAppend("Hello, World!"))
{
Console.WriteLine("Successfully appended");
}
else
{
Console.WriteLine("Buffer too small");
}ZaString significantly outperforms traditional string building approaches. Here are the actual benchmark results from comprehensive testing:
| Method | Mean Time | Memory Allocations | Performance Ratio |
|---|---|---|---|
StringBuilder (Baseline) | 146.1 ns | 480 B | 1.00x |
String concatenation | 116.3 ns | 248 B | 0.80x |
String interpolation | 116.9 ns | 136 B | 0.80x |
| ZaSpanStringBuilder | 115.2 ns | 0 B | 0.79x |
Basic String Building:
StringBuilder: 146.1 ns, 480 B allocatedStringConcatenation: 116.3 ns, 248 B allocatedStringInterpolation: 116.9 ns, 136 B allocatedNumber Formatting:
StringBuilder: 295.3 ns, 584 B allocatedLarge String Operations:
StringBuilder: 1,565.9 ns, 27,312 B allocatedDateTime Formatting:
StringBuilder: 189.0 ns, 384 B allocatedSpan vs String Processing:
StringBuilder: 24.7 ns, 256 B allocatedThese results use a builder baseline (StringBuilder.AppendFormat with InvariantCulture) for apples-to-apples comparison against ZaSpanStringBuilder (zero allocation).
| Case | Builder Mean | Builder Alloc | ZaSpan Mean | ZaSpan Alloc |
|---|---|---|---|---|
| Double | 128.70 ns | 176 B | 104.26 ns | 0 B |
| Double (Formatted F2) | 94.20 ns | 160 B | 73.33 ns | 0 B |
| Float | 105.12 ns | 168 B | 88.40 ns | 0 B |
| Long | 27.51 ns | 176 B | 12.58 ns | 0 B |
| Integer (Formatted N0) | 59.43 ns | 168 B | 38.28 ns | 0 B |
Environment: .NET 8.0.19, Ryzen 9 5950X, BenchmarkDotNet 0.15.2.
// Traditional approach - 146.1 ns, 480 B allocated
var sb = new StringBuilder();
sb.Append("Name: ").Append("John").Append(", Age: ").Append(25);
var result = sb.ToString();
// ZaString approach - 115.2 ns, 0 B allocated
Span<char> buffer = stackalloc char[50];
var builder = ZaSpanStringBuilder.Create(buffer);
builder.Append("Name: ").Append("John").Append(", Age: ").Append(25);
var result = builder.AsSpan(); // Zero allocationCreate(Span<char>) - Create a new builder with a bufferAppend() - Append various types with fluent APIAppendLine() - Append with line terminatorTryAppend() - Non-throwing append variantsAsSpan() - Get result as ReadOnlySpan<char>ToString() - Get result as string (allocates)Clear() - Reset builder for reuseSetLength(int) - Set current lengthRemoveLast(int) - Remove characters from endAppendIf() - Conditional appendingAppendJoin() - Join collections with separatorsAppendRepeat() - Repeat charactersAppendFormat() - Composite formattingAppendJsonEscaped() - JSON string escapingAppendHtmlEscaped() - HTML entity escapingAppendUrlEncoded() - URL percent encodingAppendCsvEscaped() - CSV field escapingAppendPathSegment() - URL path buildingAppendQueryParam() - URL query parameter buildingRun the comprehensive test suite:
dotnet testRun performance benchmarks:
cd tests/ZaString.Benchmarks
dotnet run -c ReleaseSee the samples directory for complete working examples demonstrating all features.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
Span<T> and Memory<T>Made with ❤️ for high-performance .NET applications