{"id":20632326,"url":"https://github.com/codybartfast/csv","last_synced_at":"2025-03-08T22:38:10.464Z","repository":{"id":41427219,"uuid":"506565791","full_name":"codybartfast/csv","owner":"codybartfast","description":"Source for the NuGet package: www.nuget.org/packages/Fmbm.Csv/","archived":false,"fork":false,"pushed_at":"2022-08-08T16:46:29.000Z","size":69,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-05T18:18:21.661Z","etag":null,"topics":["comma-separated-values","csv"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codybartfast.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-23T08:54:33.000Z","updated_at":"2022-08-08T16:01:13.000Z","dependencies_parsed_at":"2022-08-10T02:23:04.219Z","dependency_job_id":null,"html_url":"https://github.com/codybartfast/csv","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codybartfast%2Fcsv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codybartfast%2Fcsv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codybartfast%2Fcsv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codybartfast%2Fcsv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codybartfast","download_url":"https://codeload.github.com/codybartfast/csv/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242619100,"owners_count":20159001,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["comma-separated-values","csv"],"created_at":"2024-11-16T14:15:48.683Z","updated_at":"2025-03-08T22:38:10.442Z","avatar_url":"https://github.com/codybartfast.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"CSV\n===\n\nBasic reading and writing of CSV (comma-separated value) text to help share data\nwith other applications like a spreadsheet.\n\nFeatures:\n\n* Create objects from CSV text and create CSV text from objects.\n* Implicit conversion for standard types (string, DateTime, int, uint, long,\n  ulong, float, double and decimal).\n* Other types are supported with explicit conversion.\n* Specify the culture used for concersion. (Defaults to `CurrentCultue`.)\n* Intermediate data structures: `Table`, `Row`, and `Cell`, are available for\n  rudimentary editing of CSV text.\n* F# friendly.\n\n\u0026nbsp;\n\nFor Me, By Me (FMBM)\n--------------------\n\nFMBM packages are created primarily for use by the author.  They are intended\nfor getting casual, desktop applications up and running quickly.  They may not\nbe suitable for production, scalable nor critical applications. The name is\ninspired by the [Fubu][Fubu] project, '_For Us, By Us_', but there is no other\nconnection.\n\n\u0026nbsp;\n\nContents\n--------\n\n* [Basic Usage](#basic-usage)  \n  * [Creating Objects from CSV Text](#creating-objects-from-csv-text)  \n  * [Creating CSV Text from Objects](#creating-csv-text-from-objects)  \n* [Standard Types](#standard-types)  \n* [Culture](#culture)  \n* [Automatic Conversion](#automatic-conversion)  \n* [Custom Conversion](#custom-conversion)  \n* [Anonymous Types](#anonymous-types)  \n* [Tables and Rows](#tables-and-rows)  \n* [Any to Any](#any-to-any)\n* [Using With F#](#using-with-f)\n\n\u0026nbsp;\n\nBasic Usage\n-----------\n\n### Creating Objects from CSV Text\n\nGiven this CSV text for some episodes from the [second season][BbtS2] of The Big\nBang Theory:\n\n```csv\nTitle,No. overall,No. in season,Original air date,Prod. code,U.S. viewers\nThe Bad Fish Paradigm,18, 1 ,\"September 22, 2008\",3T7351,9360364\nThe Barbarian Sublimation,20, 3 ,\"October 6, 2008\",3T7353,9329673\nThe Codpiece Topology,19, 2 ,\"September 29, 2008\",3T7352,8758200\nThe Cooper-Nowitzki Theorem,23, 6 ,\"November 3, 2008\",3T7356,9670118\nThe Euclid Alternative,22, 5 ,\"October 20, 2008\",3T7355,9280649\nThe Griffin Equivalency,21, 4 ,\"October 13, 2008\",3T7354,9356497\n```\n\nWe can create `Episode` objects from this CSV Text using `CSV.GetItems`:\n\n```csharp\nusing Fmbm.Text;\n\nEpisode[] episodes = Csv.GetItems(csvTextIn, row =\u003e\n    new Episode\n    {\n        NumOverall = row(\"No. overall\"),\n        NumInSeason = row(\"No. in season\"),\n        Title = row(\"Title\"),\n        OriginalAirDate = row(\"Original air date\"),\n        USViewers = row(\"U.S. viewers\")\n    }).ToArray();\n```\n\nSignature:\n\n```csharp\n// (string, ((string -\u003e Cell) -\u003e TItem)) -\u003e IEnumerable\u003cItem\u003e\npublic static IEnumerable\u003cTItem\u003e GetItems\u003cTItem\u003e(\n        string csvText,\n        Func\u003cFunc\u003cstring, Cell\u003e, TItem\u003e makeItem)\n//          |------ row ------|\n```\n\n`makeItem` is called once for each row of the CSV text (except for the header\nrow).  `makeItem` is given a `row` function and returns a `TItem`.\n\n`row` takes a header name and returns a `Cell` containing the text for that\nposition.\n\n\u0026nbsp;\n\n### Creating CSV Text from Objects\n\nCSV text can be created from objects using  `Csv.GetText`:\n\n```csharp\nusing Fmbm.Text;\n\nstring csvTextOut = Csv.GetText(episodes,\n    (\"No. Overall\", ep =\u003e ep.NumOverall),\n    (\"No. In Season\", ep =\u003e ep.NumInSeason),\n    (\"Title\", ep =\u003e ep.Title),\n    (\"Original Air Date\", ep =\u003e ep.OriginalAirDate),\n    (\"US Viewers\", ep =\u003e ep.USViewers));\n```\n\nThis creates the following CSV text:\n\n```csv\nNo. Overall,No. In Season,Title,Original Air Date,US Viewers\n18,1,The Bad Fish Paradigm,2008-09-22 00:00,9360364\n20,3,The Barbarian Sublimation,2008-10-06 00:00,9329673\n19,2,The Codpiece Topology,2008-09-29 00:00,8758200\n23,6,The Cooper-Nowitzki Theorem,2008-11-03 00:00,9670118\n22,5,The Euclid Alternative,2008-10-20 00:00,9280649\n21,4,The Griffin Equivalency,2008-10-13 00:00,9356497\n```\n\nSignature:\n\n```csharp\n//  (IEnumerable\u003cTItem\u003e, (columnInfo, columnInfo, ...)) -\u003e string\n    public static string GetText\u003cTItem\u003e(\n        IEnumerable\u003cTItem\u003e items,\n        params (string, Func\u003cTItem, object\u003e)[] columnInfos)\n```\n\nEach `columnInfo` is a tuple comprising the header for a column and a function\nthat gets the value for that column from a `TItem`. In the example above.  The\nfirst columnInfo is `(\"No. Overall\", ep =\u003e ep.NumOverall)`.  That is, the\nheader of the first column is `\"No. Overall\"` and the value for that column\nis obtained form the `NumOverall` property of each episode.\n\nThe Episode class used in the above examples is:\n\n```csharp\nclass Episode\n{\n    public long NumOverall { get; set; }\n    public int NumInSeason { get; set; }\n    public string Title { get; set; }\n    public DateTime OriginalAirDate { get; set; }\n    public decimal USViewers { get; set; }\n}\n```\n\n\u0026nbsp;\n\nStandard Types\n--------------\n\nFor 'standard' type the `Cell` does the conversion between the text value it\nholds and the required type.\n\nThe standard types are:\n\n`string`  \n`DateTime`  \n`int`  \n`uint`  \n`long`  \n`ulong`  \n`float`  \n`double`  \n`decimal`  \n\n\u0026nbsp;\n\nCulture\n-------\n\nFor standard types `CultureInfo.CurrentCulture` is used by default to convert to\nand from text.\n\nThe culture can be specified by passing it as the second argument to `GetItems`\nof `GetText`.  E.g. to explictly use `InvariantCulture`:\n\n```csharp\nvar episodes = Csv.GetItems(csvTextIn, CultureInfo.InvariantCulture, row =\u003e\n    new Episode\n    {\n        NumOverall = row(\"No. overall\"),\n        ...\n    }).ToArray();\n```\n\n```csharp\nstring csvTextOut = Csv.GetText(episodes, CultureInfo.InvariantCulture,\n    (\"No. Overall\", ep =\u003e ep.NumOverall),\n    ...\n    );\n```\n\n\u0026nbsp;\n\nAutomatic Conversion\n--------------------\n\n### Conversion To Text\n\n`DateTime`: converts to text using the format `yyyy-MM-dd HH:mm`. (This format\nallows for the time to be included and is readable by most spreadsheet apps).\n\nThe standard numeric types are converted by calling `.ToString(\u003cculture\u003e)` on\nthe number.\n\nOther types are converted by calling `.ToString()` on the object.\n\n`null` is converted to an empty string.\n\n### Conversion From Text\n\nFor the standard types conversion from text is done by implicit conversion\noperators.\n\n`DateTime`: first a TryParseExact is attempted using the default format\n`yyyy-MM-dd HH:mm`, if that fails then `Parse` is called using the provided or\nthe default culture.  Leading and trailing whitespace is allowed.\n\nStandard numeric types are converted by calling `Parse` on the numeric type with\nthe provided or the default culture.  Leading and trailing whitespace, and\nthousands separators are allowed.\n\nThere is no automatic conversion from text to non-standard types.\n\n\u0026nbsp;\n\nCustom Conversion\n-----------------\n\nNon-standard types, and custom text formats can be supported by explictly\nproviding the CVS text or by parsing from the CVS text.  For example, to store\nthe original air date in the form `\"20:00 on 15-08-2008\"`:\n\nConverting to CSV text:\n\n```csharp\nString DateToText(DateTime date){\n    return date.ToString(\"HH:mm on dd-MM-yyyy\");\n}\n\nstring csvTextOut = Csv.GetText(episodes,\n    ...\n    (\"Original Air Date\", ep =\u003e DateToText(ep.OriginalAirDate)),\n    ...\n    );\n```\n\nConverting back to a DateTime:\n\n```csharp\nDateTime TextToDate(string text)\n{\n    return DateTime.ParseExact(text, \"HH:mm on dd-MM-yyyy\", null);\n}\n\nvar episodes = Csv.GetItems(csvTextIn, row =\u003e\n    new Episode\n    {\n        ...\n        OriginalAirDate = TextToDate(row(\"Original air date\")),\n        ...\n    }).ToArray();\n```\n\nSimilar conversion methods can be used to convert other types to and from\nCSV text.\n\nThe `row` method returns a `Cell`.  To explicitly access its content as a string\nuse the `Text` property.  For example:\n\n```csharp\nvar episodes = Csv.GetItems(csvTextIn, CultureInfo.InvariantCulture, row =\u003e\n    new Episode\n    {\n        ...\n        OriginalAirDate = TextToDate(row(\"Original air date\").Text),\n        ...\n    }).ToArray();\n```\n\nUsing the `Text` property is not needed in this case but would be necessary if\nthe conversion function took an `object`, in that case the cell's implicit\nconversion would not be called.\n\n\u0026nbsp;\n\nAnonymous Types\n---------------\n\n`GetItems` can be used to generate anonymous types.  Use explicit casts to\nspecify the type of the properties:\n\n```csharp\nvar episodes = Csv.GetItems(csvTextIn, row =\u003e\n    new\n    {\n        NumOverall = (long)row(\"No. overall\"),\n        NumInSeason = (int)row(\"No. in season\"),\n        Title = (string)row(\"Title\"),\n        OriginalAirDate = (DateTime)row(\"Original air date\"),\n        USViewers = (decimal)row(\"U.S. viewers\")\n    });\n```\n\n\u0026nbsp;\n\nTables And Rows\n---------------\n\nInternally a `Table` is created both converting from items to text\n(`IEnumerable\u003cTItem\u003e -\u003e Table -\u003e string`) or from text to items\n(`string -\u003e Table -\u003e IEnumerable\u003cTItem\u003e`).  `Fmbm.CSV` is not intended for\nediting CSV tables but `Table` does enable some basic editing.  For example, to\nput double quotes around the tites in the orignal CSV text:\n\n```csharp\nvar table = Csv.GetTable(csvTextIn);\nforeach(var row in table.Rows.Skip(1)){\n    row[0] = new Cell($\"\\\"{row[0]}\\\"\");\n}\nvar csvTextOut = Csv.GetText(table);\n```\n\n```csv\nTitle,No. overall,No. in season,Original air date,Prod. code,U.S. viewers\n\"\"\"The Bad Fish Paradigm\"\"\",18, 1 ,\"September 22, 2008\",3T7351,9360364\n\"\"\"The Barbarian Sublimation\"\"\",20, 3 ,\"October 6, 2008\",3T7353,9329673\n\"\"\"The Codpiece Topology\"\"\",19, 2 ,\"September 29, 2008\",3T7352,8758200\n\"\"\"The Cooper-Nowitzki Theorem\"\"\",23, 6 ,\"November 3, 2008\",3T7356,9670118\n\"\"\"The Euclid Alternative\"\"\",22, 5 ,\"October 20, 2008\",3T7355,9280649\n\"\"\"The Griffin Equivalency\"\"\",21, 4 ,\"October 13, 2008\",3T7354,9356497\n```\n\nNote, it was necessary to `Skip` the first row to prevent putting double quotes\narount `Title` in the headers row.\n\nUnlike reading and writing items to text, the format of the CSV text is\nunchanged.  The production code is still present, the date is in the original\nformat and the space remain around the episode number.\n\n\u0026nbsp;\n\n### Table Tolerance\n\n`GetTable` is more permisive than `GetItems` and can be used to read CSV text\nthat cannot be used by `GetItems`.  `GetItems` requires there is at least one\nrow, that the items in the first row (the headers) are unique, and that all the\nrows are of the same length.  For example, this CSV can be read by `GetTable`,\nbut would cause `GetItems` to throw an exception.\n\n```csv\nFruit,Fruit,Fruit\nApple,Banana,Cherry\nGreen,Yellow\n,,,,\n```\n\n\u0026nbsp;\n\n### Any to Any\n\n`GetItems` creates items from CSV text, or from a table.  \n`GetTable` creates a table from from CSV 'text, or from items.  \n`GetText` creates CSV text from a table, or from items.  \n\n\u0026nbsp;\n\n### Using With F\\#\n\nBecause of the differences between F# functions and C# Funcs the methods above\ndo not work 'naturally' with F#.  'getItems', 'getText' and 'getTable' are F#\nfriendly versions that accept and provide `FSharpFunc`s.  The only syntax\ndiffernce is that `columnInfos` is an IEnumerable (like a list) instead\nof `params []` in the C# methods.  That is:\n\n```fsharp\nCsv.getText(items, [(hdr, getval); (hdr, getval)])\n```\n\ninstead of:\n\n```csharp\nCsv.GetText(items, (hdr, getval), (hdr, getval))\n```\n\nHere are the original examples using F#:\n\n```fsharp\nlet episodes =\n    Csv.getItems (\n        csvTextIn,\n        fun row -\u003e\n            new Episode(\n                NumOverall = row \"No. overall\",\n                NumInSeason = row \"No. in season\",\n                Title = row \"Title\",\n                OriginalAirDate = row \"Original air date\",\n                USViewers = row \"U.S. viewers\"\n            )\n    )\n\nlet csvTextOut =\n    Csv.getText (\n        episodes,\n        [ (\"No. Overall\", (fun ep -\u003e ep.NumOverall))\n          (\"No. In Season\", (fun ep -\u003e ep.NumInSeason))\n          (\"Title\", (fun ep -\u003e ep.Title))\n          (\"Original Air Date\", (fun ep -\u003e ep.OriginalAirDate))\n          (\"US Viewers\", (fun ep -\u003e ep.USViewers)) ]\n    )\n```\n\n[Fubu]: \u003chttps://fubumvc.github.io/\u003e\n[BbtS2]: \u003chttps://en.wikipedia.org/wiki/List_of_The_Big_Bang_Theory_episodes#Season_2_(2008%E2%80%9309)\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodybartfast%2Fcsv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodybartfast%2Fcsv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodybartfast%2Fcsv/lists"}