Stringier.Patterns 0.5.1

Suggested Alternatives

Stringier

Additional Details

Features merged.

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package Stringier.Patterns --version 0.5.1
NuGet\Install-Package Stringier.Patterns -Version 0.5.1
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.
<PackageReference Include="Stringier.Patterns" Version="0.5.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Stringier.Patterns --version 0.5.1
#r "nuget: Stringier.Patterns, 0.5.1"
#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.
// Install Stringier.Patterns as a Cake Addin
#addin nuget:?package=Stringier.Patterns&version=0.5.1

// Install Stringier.Patterns as a Cake Tool
#tool nuget:?package=Stringier.Patterns&version=0.5.1

Stringier.Patterns

Patterns, probably introduced with SNOBOL, and also seen with SPITBOL and UNICON, are considerably more powerful than Regular Expressions. So what do you do when you need to parse something more complicated than a Regex? Hacky Regex extensions aren't great, and still lack what some advanced alternatives can offer. Parser Combinators? Actually these are great. I'm not going to bash them at all. Pattern Matching and Parser Combinators share a huge amount of theory and implementation details. You could consider them alternative interpretations of the same concept. That being said, you'll notice a few small differences, but the advantages apply to both.

Including

using System.Text.Patterns;

Usage

In most situations, there's only three usage patterns you'll need to know.

Declaration

Pattern patternName = "Text to match";
// Comparison of a Literal

or

Pattern patternName = ("Text to match", StringComparison.CurrentCultureIgnoreCase);
// Comparisons of this Literal will use the StringComparison value

or

Pattern patternName = literalPattern1 & (literalPattern2 | literalPattern3);
// Comparison of an actual pattern

Matching

patternName.Consume("Candidate text");
//Assuming Consume captures "Candidate" this will return true and "Candidate"

Inline (Quick Match)

"Hello".Consume("Hello World!");
//Assuming "Hello" captures "Hello" (which it obviously will) this will return true and "Hello"

Concepts

Multiple return values

Pattern matching is largely based around the idea of goal-direction. The two most likely languages you're using this library from C# and VB.NET don't support goal-direction (if you're using F# then FParsec is going to match that programming style better anyways). Goal-directed semantics require both a success state and the result to be returned from every function call (or just the success state for a void return).

But wait, C# can't return multiple values!

While true, this is remarkably pedantic. Whether you return an array, a struct, a class, or a tuple, you are returning multiple values as one conceptual value. All the parsing methods return Result which contains both the success state (Boolean) and the result of the operation (String). Result implicitly casts to both Boolean and String and can be used as such. This allows some conveniences without adding new methods.

So every return passes two values? Isn't that a lot of extra memory?

One, no not really, a single Boolean isn't very large. Two, it doesn't actually pass a Boolean at all. An empty string is recognized as a failure. Essentially Result is a box of String with special comparisons and implicit conversions. In other words, the behavior of Parse and TryParse combined into one method. And, getting technical, we're not actually passing around String either. We're actually passing around Span<Char> for performance reasons; actually passing around references to parts of the string, preventing copying in most situations.

Literal

Pattern patternName = "Literal Pattern";

This is an exact 1:1 match pattern, and is equivalent to

"pattern" == "candidate"`

Literal is meant mostly as a building block for patterns. Because pattern operators expect to use a Literal, which is not a string, the convenient syntax shown above only applies to Literal. Use inside a pattern operator might require a cast like

(Pattern)"Literal Pattern" & "Other Literal Pattern"

This is generally only required as the very first member

Alternator

Pattern patternName = pattern1 | pattern2;

Alternators accept either pattern, and are equivalent to the regex (pattern1|pattern2).

Combinator

Pattern patternName = pattern1 & pattern2;

Combinators require both patterns in sequence and are equivalent to the regex (pattern1)(pattern2) with the unnecessary parenthesis added for readability.

Optor

Pattern patternName = ~pattern;

Optors make the pattern completly optional, so success is always true, and are equivalent to the regex (pattern)?.

Repeater

Pattern patternName = pattern * 3; //repeats the pattern three times

Repeaters require the pattern to repeat the specified number of times, and can be thought of the multiplcation to patterns when combinators are addition. The above example would be equivalent to the regex pattern{3}.

Spanner

Pattern patternName = +pattern;

Spanners require the pattern to exist at least once, but will repeat until the pattern can no longer be matched, and are equivalent to the regex pattern+.

OptorSpanners

Pattern patternName = ~+pattern;

or

Pattern patternName = +~pattern;

Technically not its own type, but this does represent a Regex symbol that doesn't have a direct matching. It is equivalent to the regex pattern*.

I'm not sure if one of these forms is superior to the other. Conceptually they are the same though.

Product 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated