Use a regex instead of string.spli

Viewed 32

I had this simple code to perform a replacement on a text file based on input values provided as CSV. This works perfectly but for my knowledge, I wish to understand if it's possible to use a Regex to split on separator [,] and replace the strings in a better way

Here's my code

var csvFilename = args[0];
var templateFilename = args[1];
var outputFilename = args[2];

var splitChar = ",";

var csvContent = File.ReadAllLines(csvFilename);
var templateFilenameContent = File.ReadAllText(templateFilename);

using var outputFile = new StreamWriter(outputFilename);

foreach (var s in csvContent)
{

  var splitted = s.Split(splitChar);

  StringBuilder sb = new StringBuilder(templateFilenameContent);

  sb.Replace("{DATASET_ID}", splitted[0]);
  sb.Replace("{URL}", splitted[1]);

  outputFile.WriteLine(sb);

}

Thanks

1 Answers

What you posted isn't a replacement. It's using data from the CSV file to generate new text based on a template. Using a regular expression for replacement means you'd still have to parse the pattern for every line.

All Regex.Replace overloads search for a pattern in an input and replace it with the provided text. This means for every line, Regex.Replace would have to be called to parse the template and replace the placeholders with data from the CSV file.

Using a template engine

You should consider using a template engine like Scriban instead. You could create a template eg:

var template = Template.Parse(@"
<ul id='dataset'>
  {{ for dataset in Datasets}}
    <li>
      <a href='{{ dataset.Url }}>{{ dataset.DatasetID }}</a>
    </li>
  {{ end }}
</ul>
");

And generate the entire file at once using the parsed data:

var result = template.Render(new { Datasets = setList });

You can reduce memory consumption by using File.ReadLines instead of File.ReadAllLines so that only a single line is read at a time.

record MySet(string DatasetID,string Url);

var setList=from line in File.ReadLines(csvPath)
            let parts=line.Split(splitChar)
            select new MySet(parts[0],parts[1]);

Another possibility is to use a library like CsvHelper to parse the CSV file directly into classes, handling headers, conversions, delimiters and more:

using var reader = new StreamReader("path\\to\\file.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture));

var sets= csv.GetRecords<MySet>();

var result = template.Render(new { Datasets = sets });

You can configure the delimiter, headers and more through configuration:

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    HasHeaderRecord = false,
    Delimiter = "|",
};
using var reader = new StreamReader("path\\to\\file.csv");
using var csv = new CsvReader(reader, configuration);
Related