Parsley.Net 1.0.1

dotnet add package Parsley.Net --version 1.0.1
                    
NuGet\Install-Package Parsley.Net -Version 1.0.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="Parsley.Net" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Parsley.Net" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Parsley.Net" />
                    
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 Parsley.Net --version 1.0.1
                    
#r "nuget: Parsley.Net, 1.0.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.
#addin nuget:?package=Parsley.Net&version=1.0.1
                    
Install Parsley.Net as a Cake Addin
#tool nuget:?package=Parsley.Net&version=1.0.1
                    
Install Parsley.Net as a Cake Tool

Parsley.Net v1.0.1

NuGet version License: MIT GitHub Release master-build master-codeql .Net 9.0

Introduction

What is Parsley.Net?

Parsley.Net is a .net utility to help parse Fixed Width or Delimiter Separated file using strongly typed objects.

It is a simple and easy to use library that can be used to parse delimeter separated files in .net applications. It is designed to be lightweight and fast, making it ideal for use in high-performance applications.

What is Fixed width or Delimiter separated text file?

Fixed width or Delimiter separated text file is a file that has a specific format which allows for the manipulation of textual information in an organized fashion.

  • Each row contains one record of information; each record can contain multiple pieces of data fields or columns.
  • The data columns are separated by any character you specify called the delimiter.
  • All rows in the file follow a consistent format and should be with the same number of data columns.
  • Data columns could be empty with no value.

Example: Simple pipe '|' separated Delimeter File is shown below (this could even be comma ',' separated CSV)

|Mr|Jack Marias|Male|London, UK|Active|||
|Dr|Bony Stringer|Male|New Jersey, US|Active||Paid|
|Mrs|Mary Ward|Female||Active|||
|Mr|Robert Webb|||Active|||

Getting Started?

i. Installation

Install the latest version of Parsley.Net nuget package with command below.

NuGet\Install-Package Parsley.Net 

ii. Implementation: Using Parsley.Net

<ins>Step 1<ins>. Initialise and use Parser class.

Parser is an implementation of IParser interface that provides methods for

  • parsing content of a file by specifying the file path
  • parsing an array of delimiter separated strings

Please see below.

  public interface IParser
  {
     public T[] Parse<T>(string filepath) where T : IFileLine, new();
     public T[] Parse<T>(string[] lines) where T : IFileLine, new();
  }

To initialise Parser class you could do it manually or use dependency injection as shown below. The parser class has parameterised constructor that takes the delimiter character to initialise the instance. Default character is ',' (comma) to initialise the parser for a CSV file parsing.

Example of Manual Instantiation is

 var parser = new Parser('|');

Example of IoC is

var services = new ServiceCollection();

services.AddTransient(typeof(IParser), c => new Parser(','));
// or use extension method
services.UseParsley('|');

serviceProvider = services.BuildServiceProvider();
var parser = serviceProvider.GetService<IParser>();
<ins>Step 2<ins>. Define the IFileLine implementation to parse a file record into a strongly typed line class.

Consider the file below. To parse a row into a C# class, you need to implement IFileLine interface. By doing this you create a strongly typed line representation for each row in the file.

|Mr|Jack Marias|Male|London, UK|
|Dr|Bony Stringer|Male|New Jersey, US|
|Mrs|Mary Ward|Female||
|Mr|Robert Webb|||

Let us create an employee class which will hold data for each row shown in the file above. The properties in the line class should match to the column index and data type of the fields of the row.

We use the column attribute to specify the column index and can optionally specify a default value for the associated column should it be be empty. As a rule of thumb, the number of properties with column attributes should match the number of columns in the row else the parser will throw an exception.

IFileLine interface provides

  • Index property that holds the index of the parsed line relative to the whole file,
  • Errors property which is an array representing any column parsing failures.

Please see below.

public interface IFileLine
{
    public int Index { get; set; }
    public IList<string> Errors { get; set; }
}

Example. Employee class

public class Employee : IFileLine
{
    // Custom column properties

    [Column(0)]
    public string Title { get; set; }
    [Column(1)]
    public string Name { get; set; }
    [Column(2)]
    public EnumGender Sex { get; set; }
    [Column(3, "London, UK")]
    public string Location { get; set; }

    // IFileLine Members
    public int Index { get; set; }
    public IList<string> Errors { get; set; }
} 

Once you have created the line class it is as simple as calling one of the parser.Parse() methods below

  1. By providing the path of the file to parse method.
var records = new Parser('|').Parse<Employee>("c://employees.txt");
  1. By providing the list of delimiter separated string values to parse method.
 var lines = new[]
 {
      "|Mr|Jack Marias|Male|London, UK|",
      "|Dr|Bony Stringer|Male|New Jersey, US|",
 };

var records = new Parser('|').Parse<Employee>(lines);
<ins>Step 3<ins>. Advanced Parsing of data using nested types in the FileLine class.

Case 1: Write your own Custom Converter to parse data to a custom type.

You could implement advance parsing of data by implementing TypeConverter class. Suppose we have to change the Name string property in Employee class above to a NameType property shown below.

public class Employee : IFileLine
{
    [Column(0)]
    public string Title { get; set; }
    [Column(1)]
    public NameType Name { get; set; }
    [Column(2)]
    public EnumGender Sex { get; set; }
    [Column(3, "London")]
    public string Location { get; set; }

    // IFileLine Members
    public int Index { get; set; }
    public IList<string> Errors { get; set; }
}

public class NameType
{
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

In order to parse the string value (name) from delimiter separated record in the file correctly to custom type (NameType), you need to implement custom converter deriving from TypeConverter class.

Example - NameConverter class - converts name string value to NameType instance

public class NameConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        string stringValue;
        object result;

        result = null;
        stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue))
        {
            result = NameType.Parse(stringValue);
        }

        return result ?? base.ConvertFrom(context, culture, value);
    }
}

After implementing the custom TypeConverter, you need to decorate the NameType class with [TypeConverter(typeof(NameConverter))] attribute.

[TypeConverter(typeof(NameConverter))]
public class NameType
{
    public string FirstName { get; set; }
    public string Surname { get; set; }

    public static NameType Parse(string input)
    {
        var values = input.Split(' ');

        if (values.Length == 1)
            return new NameType { FirstName = values[0] };

        if (values.Length == 2)
            return new NameType { FirstName = values[0], Surname = values[1] };

        if (values.Length > 2)
        {
            var forenames = string.Empty;
            for (var i = 0; i < values.Length - 1; i++)
                forenames += string.Concat(values[i]) + " ";

            return new NameType { FirstName = forenames.Trim(), Surname = values[values.Length - 1] };
        }

        return new NameType { FirstName = input };
    }
}

Now parsing the file should hydrate the name correctly to the Employee FileLine class with nested name type.

Case 2: Use CustomeConverter<T> included with Parsely, where T is the custom type.

Please see example below on how out of the box converter can be used in defining custom LocationType class to include in Employee line class.

public class Employee : IFileLine
{
    [Column(0)]
    public string Title { get; set; }
    [Column(1)]
    public NameType Name { get; set; }
    [Column(2)]
    public EnumGender Sex { get; set; }
    [Column(3, "London, UK")]
    public LocationType Location { get; set; }

    // IFileLine Members
    public int Index { get; set; }
    public IList<string> Errors { get; set; }
}

You need to derive the custom LocationType type from ICustomType and implement the Parse(string) method. You also need to decorate the custom type with [TypeConverter(typeof(CustomConverter<LocationType>))] attribute.

[TypeConverter(typeof(CustomConverter<LocationType>))]
public class LocationType : ICustomType
{
    public string City { get; set; }
    public string Country { get; set; }

    public ICustomType Parse(string input)
    {
        var values = input.Split(',');
        if (values.Length == 1)
            return new LocationType { City=values[0] };
        if (values.Length == 2)
            return new LocationType { City=values[0], Country=values[1] };

       // return default - London, UK
        return new LocationType { City="London", Country="UK" };
    }
}

Now parsing the file should hydrate the location value correctly to the Employee FileLine class with nested LocationType type.

Support

If you are having problems, please let me know by raising a new issue.

License

This project is licensed with the MIT license.

Version History

The main branch is now on .NET 9.0. | Version | Release Notes | | -------- | --------| | v1.0.0 | Notes |

Credits

Thank you for reading. Please fork, explore, contribute and report. Happy Coding !! 😃

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.  net9.0 is compatible.  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 was computed.  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. 
.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 is compatible. 
.NET Framework net461 was computed.  net462 is compatible.  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 (1)

Showing the top 1 NuGet packages that depend on Parsley.Net:

Package Downloads
FixedWidth.FileParser

.Net Library to read from fixed width or delimiter separated file using strongly typed objects. Example: pipe delimited, csv, tsv, etc.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.1 227 5/16/2025
1.0.0 162 5/8/2025

v1.0 - Targets .Net9.0
* Includes core functionality for parsing delimiter separated files.