Nemesis.TextParsers
0.9.7
See the version list below for details.
dotnet add package Nemesis.TextParsers --version 0.9.7
NuGet\Install-Package Nemesis.TextParsers -Version 0.9.7
<PackageReference Include="Nemesis.TextParsers" Version="0.9.7" />
paket add Nemesis.TextParsers --version 0.9.7
#r "nuget: Nemesis.TextParsers, 0.9.7"
// Install Nemesis.TextParsers as a Cake Addin #addin nuget:?package=Nemesis.TextParsers&version=0.9.7 // Install Nemesis.TextParsers as a Cake Tool #tool nuget:?package=Nemesis.TextParsers&version=0.9.7
Nemesis.TextParsers
When stucked with a task of parsing various items form strings we ofter opt for TypeConverter (https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.typeconverter) ?
We tend to create methods like:
public static T FromString<T>(string text) =>
(T)TypeDescriptor.GetConverter(typeof(T))
.ConvertFromInvariantString(text);
or even create similar constructs to be in line with object oriented design:
public abstract class TextTypeConverter : TypeConverter
{
public sealed override bool CanConvertFrom(ITypeDescriptorContextcontext, Type sourceType) =>
sourceType == typeof(string) || base.CanConvertFrom(context, ourceType);
public sealed override bool CanConvertTo(ITypeDescriptorContext ontext, Type destinationType) =>
destinationType == typeof(string) || base.CanConvertTocontext, destinationType);
}
public abstract class BaseTextConverter<TValue> : TextTypeConverter
{
public sealed override object ConvertFrom(ITypeDescriptorContext ontext, CultureInfo culture, object value) =>
value is string text ? ParseString(text) : default;
public abstract TValue ParseString(string text);
public sealed override object ConvertTo(ITypeDescriptorContext ontext, CultureInfo culture, object value, Type estinationType) =>
destinationType == typeof(string) ?
FormatToString((TValue)value) :
base.ConvertTo(context, culture, value, destinationType);
public abstract string FormatToString(TValue value);
}
What is wrong with that? Well, nothing... except of performance.
TypeConverter was designed 15+ years ago when processing power tended to double every now and then and (in my opinion) it was more suited for creating GUI-like editors where performance usually is not an issue. But imagine a service application like exchange trading suite that has to perform multiple operations per second and in such cases processor has more important thing to do than parsing strings.
Parser requirements vs implemented features
- has to be as concise as possible - both JSON or XML exist but thay are not ready to be created from hand by human support
- has to work in various architecture supporting .net Core and .net Standard and be culture independent
- has to support basic system types (C#-like type names):
- string
- bool
- byte/sbyte
- short/ushort
- int/uint
- long/ulong
- float/double
- decimal
- BigInteger
- TimeSpan
- DateTime/DateTimeOffset
- Guid
- has to support pattern based parsing/formatting via ToString/FromText methods placed inside type or static/instance factory
- has to support compound types:
- KeyValuePair<,>
- Enums (with number underlying types)
- Nullables
- Dictionaries (including SortedDictionary/SortedList)
- Arrays (including jagged arrays)
- Standard collections and collection contracts (List vs IList vs IEnumerable)
- User defined collections
- everything mentioned above but combined with inner elements properly escaped in final string i.e. SortedDictionary<char, IList<float[][]>>
- has to be able to fallback to TypeConverter if no parsing/formatting strategy was found
- has to be fast to parse while allocating as little memory as possible upon parsing
Method | Mean | Ratio | Gen 0 | Gen 1 | Allocated | Remarks |
---|---|---|---|---|---|---|
RegEx parsing | 4,528.99 us | 44.98 | 492.1875 | - | 2089896 B | Regular expression with escaping support |
StringSplitTest_KnownType | 93.41 us | 0.92 | 9.5215 | 0.1221 | 40032 B | string.Split(..).Select(text=>int.Parse(text)) |
StringSplitTest_DynamicType | 474.73 us | 4.69 | 24.4141 | - | 104032 B | string.Split + TypeDescriptor.GetConverter |
SpanSplitTest_NoAlloc | 101.00 us | 1.00 | - | - | - | "1|2|3".AsSpan().Tokenize() |
SpanSplitTest_Alloc | 101.38 us | 1.00 | 0.8545 | - | 4024 B | "1|2|3".AsSpan().Tokenize(); var array = new int[1000]; |
- has to provide basic building blocks for parser's callers to be able to create their own transformers/factories
- LeanCollection type has to be provided
- string.Split equivalent has to be provided to accept faster representaion of string - ReadOnlySpan<char>. Both standard/escaping sequence supporting versions have to be implemented
- basic LINQ support
var avg = SpanCollectionSerializer.DefaultInstance.ParseStream<double>("1|2|3".AsSpan()).Average();
- basic support for GUI editors for compound types like collections/dictionaries
- lean/frugal implementation of StringBuilder - ValueSequenceBuilder
Span<char> initialBuffer = stackalloc char[32];
var accumulator = new ValueSequenceBuilder<char>initialBuffer);
using (var enumerator = coll.GetEnumerator())
while (enumerator.MoveNext())
FormatElement(formatter, enumerator.Current, ref ccumulator);
var text = accumulator.AsSpanTo(accumulator.Length > 0 ? ccumulator.Length - 1 : 0).ToString();
accumulator.Dispose();
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 is compatible. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 2.2
- Nemesis.Essentials (>= 1.0.10)
- System.Runtime.CompilerServices.Unsafe (>= 4.5.2)
-
.NETStandard 2.0
- Nemesis.Essentials (>= 1.0.10)
- System.Memory (>= 4.5.2)
- System.Runtime.CompilerServices.Unsafe (>= 4.5.2)
- System.ValueTuple (>= 4.5.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Nemesis.TextParsers:
Package | Downloads |
---|---|
Nemesis.Demos
Set of utils for showing coding and language/framework features in form of live demos This package was built from the source at https://github.com/nemesissoft/Nemesis.Demos/tree/dcb94c7943b7275519e5994167a812cba983e01d |
|
Nemesis.TextParsers.DependencyInjection
Contains helper methods useful to setup DependencyInjection using Microsoft.Extensions.DependencyInjection This package was built from the source at https://github.com/nemesissoft/Nemesis.TextParsers/tree/e0a38ccb3e4232df89c2e1737b5316fe91462790 |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.9.15 | 197 | 8/9/2024 |
2.9.6 | 146 | 8/8/2024 |
2.9.2 | 232 | 1/3/2024 |
2.9.1 | 127 | 1/1/2024 |
2.8.2 | 148 | 12/19/2023 |
2.7.2 | 279 | 7/16/2023 |
2.7.1 | 167 | 7/14/2023 |
2.7.0 | 154 | 7/14/2023 |
2.6.3 | 487 | 5/30/2022 |
2.6.2 | 427 | 3/1/2021 |
2.6.1 | 360 | 2/25/2021 |
2.6.0 | 383 | 2/25/2021 |
2.5.0 | 409 | 12/31/2020 |
2.4.0 | 426 | 11/30/2020 |
2.3.0 | 429 | 11/16/2020 |
2.2.1 | 538 | 5/15/2020 |
2.2.0 | 431 | 5/14/2020 |
2.1.2 | 446 | 5/12/2020 |
2.1.1 | 500 | 5/1/2020 |
2.1.0 | 464 | 4/28/2020 |
2.0.4 | 468 | 4/26/2020 |
2.0.2 | 483 | 4/21/2020 |
2.0.1 | 486 | 4/17/2020 |
2.0.0-alpha | 352 | 4/15/2020 |
1.5.1 | 465 | 3/29/2020 |
1.5.0 | 505 | 3/28/2020 |
1.4.1 | 525 | 3/23/2020 |
1.3.2 | 495 | 3/19/2020 |
1.3.0 | 497 | 3/16/2020 |
1.2.0 | 559 | 3/15/2020 |
1.1.3 | 579 | 3/14/2020 |
1.1.2 | 550 | 2/27/2020 |
1.1.1 | 492 | 2/26/2020 |
1.1.0 | 548 | 2/26/2020 |
1.0.6 | 565 | 2/25/2020 |
1.0.4 | 439 | 2/25/2020 |
1.0.3 | 563 | 2/18/2020 |
1.0.2 | 552 | 11/8/2019 |
1.0.1 | 508 | 11/6/2019 |
1.0.0 | 513 | 9/25/2019 |
0.11.50 | 522 | 9/25/2019 |
0.11.47 | 505 | 9/25/2019 |
0.11.46 | 518 | 9/23/2019 |
0.11.42 | 557 | 9/18/2019 |
0.11.41 | 518 | 9/18/2019 |
0.11.40 | 511 | 9/18/2019 |
0.11.39 | 575 | 9/18/2019 |
0.11.38 | 536 | 9/18/2019 |
0.11.37 | 517 | 9/18/2019 |
0.11.36 | 534 | 9/17/2019 |
0.11.35 | 535 | 9/17/2019 |
0.11.34 | 535 | 9/17/2019 |
0.11.33 | 545 | 9/17/2019 |
0.9.32 | 538 | 9/17/2019 |
0.9.31 | 527 | 9/11/2019 |
0.9.30 | 545 | 9/9/2019 |
0.9.29 | 524 | 9/6/2019 |
0.9.28 | 543 | 8/3/2019 |
0.9.27 | 561 | 8/3/2019 |
0.9.26 | 522 | 8/1/2019 |
0.9.25 | 561 | 7/21/2019 |
0.9.24 | 550 | 7/19/2019 |
0.9.22 | 558 | 6/14/2019 |
0.9.21 | 541 | 6/13/2019 |
0.9.20 | 592 | 6/9/2019 |
0.9.19 | 616 | 6/7/2019 |
0.9.18 | 596 | 6/5/2019 |
0.9.15 | 554 | 5/29/2019 |
0.9.14 | 605 | 5/29/2019 |
0.9.13 | 587 | 5/28/2019 |
0.9.12 | 585 | 5/27/2019 |
0.9.10 | 601 | 5/21/2019 |
0.9.8 | 574 | 5/7/2019 |
0.9.7 | 596 | 5/5/2019 |
0.9.6 | 578 | 5/5/2019 |
0.9.5 | 558 | 5/5/2019 |
0.0.0-alpha.0.335 | 79 | 1/1/2024 |