Live data from Hacker News

World's Smallest CSV Parser (C#)

github.com

61–70 of 72 posts

Re: World's Smallest CSV Parser (C#)

#61

That’s still multiple lines of code. Here’s one in c++ that uses only a single line of code (excluding function headers) // How do I format this as code? vector split( const string& s) { return accumulate(s.begin(), s.end(), vector (1), [=](auto acc, char c) { if (c == ‘,’){ acc.push_back(string()); } else { acc.back( ) += c; } return acc; } ); }

Does it parse this, though? "Verne, Jules", "20,000 leagues under the sea"

Wrap it in a second function that parses out quotes and bit-stuffs the commas with something else.

Re: World's Smallest CSV Parser (C#)

#62
post #37

Earlier quoted context omitted.

I'm not seeing where it says not to throw InvalidOperationException.

InvalidOperationException means "the object is in an inappropriate state". That does not describe a parse error. C# conventions for exceptions are admittedly a bit confusing. There are a handful of very specific scenarios where you're supposed to use a built-in exception (most commonly ArgumentException). For everything else, you want to define your own type.

The state of the stream, such that it's pointing to an illegal character, actually does seem to be invalid though. Maybe this is an overly pedantic argument. I've been writing quite a bit of c# for over a decade and have basically been doing this the whole time. I thought that I knew how to use exceptions, but it seems I do not.

Re: World's Smallest CSV Parser (C#)

#63

Questions: 1. What is the size of the install required to get C# to run on a computer without Windows or MacOS installed 2. What is the size of the install for this C# library Just curious

App with runtime would probably be around 30 MBs?

dotnet publish -c Release -r linux-x64 -o output -p:PublishTrimmed=true

or 100MB without trimming

Re: World's Smallest CSV Parser (C#)

#65
post #9

Earlier quoted context omitted.

C# `char` is a UTF-16 code unit. It does not indicate a byte which is just `byte`. Having StringBuilder be a private field on the parser instance is not an issue either - it is simply reused.

Iterating over the `char`s does not support the full range of what can be stored in a C# string (for instance, UTF-8 graphemes that are serialized as surrogate pairs are usually two `char`s in a C# string. .Net provides a TextElementEnumerator that will iterate over graphemes instead: https://learn.microsoft.com/en-us/dotnet/api/system.globaliz... There's a fairly comprehensive guide to working with .net character en…

The unit tests have an emoji test (which uses a surrogate pair). I thought I would have to use Runes, but it's not necessary. https://github.com/kjpgit/SmallestCSVParser/blob/master/Smal...

Re: World's Smallest CSV Parser (C#)

#66

Questions: 1. What is the size of the install required to get C# to run on a computer without Windows or MacOS installed 2. What is the size of the install for this C# library Just curious

App with runtime would probably be around 30 MBs? dotnet publish -c Release -r linux-x64 -o output -p:PublishTrimmed=true or 100MB without trimming

AOT-built /Example should be <= 2MB (like most of them regardless of the library), since the library itself can only be consumed by .NET and its assembly would take a couple dozens of KB at most.

Re: World's Smallest CSV Parser (C#)

#67
post #7

What's the utility of defining the "Error" exception. Why not use an existing one, say InvalidOperationException, or a plain Exception. Is making your own better practice?

There is no utility. It's perhaps written for JavaScript developers who are used to Error.. but it's not idiomatic C#. Might be indicative of a copilot too. The use of a class-scoped `StringBuilder` that only one method uses, and `ReadQuotedColumn`/`ReadNonQuotedColumn` yielding one character at a time, rather than accepting a the builder isn't a good sign either (for efficiency). Or casting everything to a `char` (t…

I will add a micro benchmark to see if the `yield return` is slowing things down, compared to just calling _sb.Add() inside Read*(). I will also see if it looks cleaner that way. To be honest, the `yield return` is currently in there just because I thought it's "cool".

Re: World's Smallest CSV Parser (C#)

#68
post #44
post #42

It's a nice tidy CSV parser, but needs a new title. "world's smallest" is never going to happen in C#, for any measure of "smallest". And aside from that, nobody should be rolling their own CSV parsers if they want to solve real-world problems; use the most capable library your language offers you, which will account for a hundred edge cases yours doesn't.

Funny story re "nobody should be rolling": When I was switching from academia to industry, I decided, based on HN comments like this, that I should un-publish my CSV parser. I was worried potential employers would tsk-tsk me for self-rolling. I promptly got an email from the creator of Ruby asking me why I had un-published my CSV parser, which apparently was being used in Ruby at the time. (...And then later I landed…

Well, it depends if your self-rolled version is a complete library, or a quick sidetrack you implemented as a bigger project. If you published it as an installable independent library, and Ruby was using it, I think it's safe to say that you had a complete product. The evil of self-rolled CSV is that people often build on an incomplete understanding of the problem, don't have unit tests, or do something simplistic that necessitates workarounds like this: https://metacpan.org/pod/Data::TableReader::Decoder::IdiotCS...

(case in point, that crazy workaround is only possible because of a large expenditure of effort by the authors of perl's Text::CSV which very few CSV parsers would have implemented)

Re: World's Smallest CSV Parser (C#)

#69
post #64

`column.Substring(1, column.Length - 2)` could use the new-ish range indexing syntax. column[1..^1]

Thanks... I didn't think that would compile on .net 6, but it does!

You can probably shorten it to

    column[1..]
and it compiles down to a Substring call, and ranges are part of C# 8, so they exist since .NET Core 3.1. But even if the syntax is newer (e.g. collection expressions in C# 12) you can often also use features on older target frameworks if they don't require additional runtime support (and even that can often be retrofitted internally).

Re: World's Smallest CSV Parser (C#)

#70
post #7

What's the utility of defining the "Error" exception. Why not use an existing one, say InvalidOperationException, or a plain Exception. Is making your own better practice?

There is no utility. It's perhaps written for JavaScript developers who are used to Error.. but it's not idiomatic C#. Might be indicative of a copilot too. The use of a class-scoped `StringBuilder` that only one method uses, and `ReadQuotedColumn`/`ReadNonQuotedColumn` yielding one character at a time, rather than accepting a the builder isn't a good sign either (for efficiency). Or casting everything to a `char` (t…

30% performance improvement after removing the `yield return`, and readability is probably better too.
Post reply on HN